money_exchange 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b36c0d6c30f6817a4b21698f93ff5d483bf69be3
4
+ data.tar.gz: 513af7e1ce9c8c3ad88eaec9a28d18c1e7bca454
5
+ SHA512:
6
+ metadata.gz: 1a21a6862dff4852dfea6042dcec738df8234bb36c6e85a25b65891adfad26fbcec70ae2fccf1127398101bd2d4ef35492337b974c17601b9fbad41311bc35c5
7
+ data.tar.gz: b603e13e5993fb0098fe4e849488608fe390ed2f97b31fcff2412b54a7c1b6b2a1a18cbe8683b3ee88d0865e1d376ea01b546ccc6f3e3a20bcb179807ea00467
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in money_exchange.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 kyoendo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # MoneyExchange
2
+
3
+ Just another currency converter based on [Google's Currency Converter and JSON API](http://motyar.blogspot.jp/2011/12/googles-currency-converter-and-json-api.html "Google's Currency Converter and JSON API").
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'money_exchange'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install money_exchange
18
+
19
+ ## Usage
20
+
21
+ Require it and available `#xxx_to_yyy` and `#xxx_to` for Fixnum and String.
22
+
23
+ ```ruby
24
+ 1.usd_to_jpy
25
+ # => 98.46
26
+
27
+ 1.usd_to(:jpy, :eur, :mxn)
28
+ # => [98.46, 0.74, 12.97]
29
+ ```
30
+
31
+ ## Command
32
+
33
+ It comes with `money_exchange` command. Just type it on your terminal and read the help.
34
+
35
+ ## Thank you
36
+
37
+ I got some hits from [codegram/simple_currency](https://github.com/codegram/simple_currency). Thank you.
38
+
39
+ ## Contributing
40
+
41
+ 1. Fork it
42
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
43
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
44
+ 4. Push to the branch (`git push origin my-new-feature`)
45
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'money_exchange'
4
+
5
+ MoneyExchange::Command.start(ARGV)
6
+
@@ -0,0 +1,87 @@
1
+ require "money_exchange/version"
2
+ require "money_exchange/core_ext"
3
+ require "money_exchange/command"
4
+ require "open-uri"
5
+ require "json"
6
+
7
+ module MoneyExchange
8
+
9
+ # Presume '#xxx_to' style methods as for money exchanges
10
+ def method_missing(meth, *a, &b)
11
+ case meth
12
+ when /^([a-z]{3})_to_([a-z]{3})$/
13
+ currency, target = $~.captures
14
+ Money.new(self, currency).send("to_#{target}")
15
+ when /^([a-z]{3})_to$/
16
+ currency, targets = $~[1], a
17
+ targets.map { |t| Money.new(self, currency).send("to_#{t}") }
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ class Money
24
+ attr_reader :amount, :currency
25
+ def initialize(amount, currency)
26
+ @amount = Float(amount)
27
+ @currency = currency
28
+ end
29
+
30
+ def method_missing(meth, *a, &b)
31
+ case meth
32
+ when /^to_([a-z]{3})$/
33
+ Exchange.calc(self, $~[1])
34
+ else
35
+ super
36
+ end
37
+ end
38
+ end
39
+
40
+ class Exchange
41
+ class NoCurrencyDataError < StandardError; end
42
+
43
+ class << self
44
+ def calc(money, target)
45
+ res = money.amount * rate(money.currency, target)
46
+ (res * 100).round.to_f / 100
47
+ end
48
+
49
+ private
50
+ def rate(base, target)
51
+ response = call_google_currency_api(base, target)
52
+ rate = parse_rate(response)
53
+ end
54
+
55
+ def parse_rate(response)
56
+ body = JSON.parse(fix_json response)
57
+
58
+ if ['0', ''].include?(body['error']) # when no error
59
+ body['rhs'].split(',')[0].to_f
60
+ else
61
+ raise NoCurrencyDataError
62
+ end
63
+ end
64
+
65
+ # Because Google Currency API returns a broken json.
66
+ def fix_json(json)
67
+ json.gsub(/(\w+):/, '"\1":')
68
+ end
69
+
70
+ def call_google_currency_api(base, target)
71
+ uri = "http://www.google.com/ig/calculator"
72
+ query = "?hl=en&q=1#{base}=?#{target}"
73
+ URI.parse(uri+query).read
74
+ rescue OpenURI::HTTPError => e
75
+ abort "HTTP Access Error:#{e}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ class Numeric
82
+ include MoneyExchange
83
+ end
84
+
85
+ class String
86
+ include MoneyExchange
87
+ end
@@ -0,0 +1,69 @@
1
+ require "thor"
2
+
3
+ module MoneyExchange
4
+ class Command < Thor
5
+ desc "ex AMOUNT BASE *TARGETS", "Currency Exchange from base to targets"
6
+ def ex(amount, base, *targets)
7
+ results = amount.send("#{base.downcase}_to", *targets.map(&:downcase))
8
+ print_in_format(amount, base, targets, results)
9
+ rescue Exchange::NoCurrencyDataError
10
+ abort "no exchange data for any of them. see help."
11
+ rescue
12
+ abort "you might pass wrong codes. see help."
13
+ end
14
+
15
+ no_commands do
16
+ def print_in_format(amount, base, targets, results)
17
+ from = "#{base.upcase} #{amount} => "
18
+ padding = ' ' * from.size
19
+ head = [from] + [padding] * targets.size
20
+ head.zip(targets.map(&:upcase), results).map do |h, t, r|
21
+ h = h.sub(/^\w{3}/) { "#{c $&, 32}" }
22
+ puts "%s%s %s" % [h, c(t), r]
23
+ end
24
+ end
25
+
26
+ def c(str, d='32')
27
+ "\e[#{d}m#{str}\e[0m"
28
+ end
29
+ end
30
+
31
+ desc "version", "Show MoneyExchange version"
32
+ def version
33
+ puts "MoneyExchange #{MoneyExchange::VERSION} (c) 2013 kyoendo"
34
+ end
35
+ map "-v" => :version
36
+
37
+ desc "banner", "Describe MoneyExchange usage", hide:true
38
+ def banner
39
+ banner = ~<<-EOS
40
+ Available currency codes:
41
+ AUD: Australian dollar
42
+ CAD: Canadian dollar
43
+ CHF: Swiss franc
44
+ CNY: Chinese yuan
45
+ DKK: Danish krone
46
+ EUR: Euro
47
+ GBP: British pound
48
+ HKD: Hong Kong dollar
49
+ HUF: Hungarian forint
50
+ INR: Indian rupee
51
+ JPY: Japanese yen
52
+ MXN: Mexican peso
53
+ NOK: Norwegian krone
54
+ NZD: New Zealand dollar
55
+ PLN: Polish złoty
56
+ SEK: Swedish krona
57
+ SGD: Singapore dollar
58
+ TRY: Turkish lira
59
+ USD: United States Dollar
60
+ ZAR: South African rand
61
+ EOS
62
+ help
63
+ puts banner
64
+ end
65
+ default_task :banner
66
+ map "-h" => :banner
67
+ end
68
+ end
69
+
@@ -0,0 +1,7 @@
1
+ class String
2
+ def ~
3
+ margin = scan(/^ +/).map(&:size).min
4
+ gsub(/^ {#{margin}}/, '')
5
+ end
6
+ end
7
+
@@ -0,0 +1,3 @@
1
+ module MoneyExchange
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'money_exchange/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "money_exchange"
8
+ spec.version = MoneyExchange::VERSION
9
+ spec.authors = ["kyoendo"]
10
+ spec.email = ["postagie@gmail.com"]
11
+ spec.description = %q{Just another currency converter}
12
+ spec.summary = %q{Just another currency converter using Google currency converter API.}
13
+ spec.homepage = "https://github.com/melborne/money_exchange"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "thor"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "fakeweb"
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require "stringio"
3
+
4
+ describe MoneyExchange::Command do
5
+ before(:each) do
6
+ FakeWeb.clean_registry
7
+ $stdout = StringIO.new
8
+ end
9
+
10
+ describe '#ex command' do
11
+ it 'returns exchanged amount' do
12
+ mock_google_currency_api('usd', 'jpy')
13
+ argv = ['ex', '1.00', 'usd', 'jpy']
14
+ MoneyExchange::Command.start(argv)
15
+ res = "\e[32mUSD\e[0m 1.00 => \e[32mJPY\e[0m 100.31\n \e[32m\e[0m"
16
+ expect($stdout.string.strip).to eql res
17
+ end
18
+ end
19
+
20
+ after(:each) do
21
+ $stdout = STDOUT
22
+ end
23
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe MoneyExchange do
4
+ it 'should have a version number' do
5
+ MoneyExchange::VERSION.should_not be_nil
6
+ end
7
+ end
8
+
9
+ describe Numeric do
10
+ let(:nocurrency_error) { MoneyExchange::Exchange::NoCurrencyDataError }
11
+
12
+ before(:each) do
13
+ FakeWeb.clean_registry
14
+ end
15
+
16
+ describe '#xxx_to_yyy' do
17
+ context 'convert self in XXX currency to YYY currency' do
18
+ it 'exchanges USD to JPY' do
19
+ mock_google_currency_api('usd', 'jpy')
20
+ expect(1.00.usd_to_jpy).to eql(100.31)
21
+ end
22
+
23
+ it 'exchanges JPY to USD' do
24
+ mock_google_currency_api('jpy', 'usd')
25
+ expect(150.jpy_to_usd).to eql(1.50)
26
+ end
27
+
28
+ it 'exchanges EUR to USD' do
29
+ mock_google_currency_api('eur', 'usd')
30
+ expect(1.23.eur_to_usd).to eql(1.62)
31
+ end
32
+
33
+ it 'raise NoCurrencyDataError' do
34
+ mock_google_currency_api('jpy', 'xxx')
35
+ expect { 100.jpy_to_xxx }.to raise_error(nocurrency_error)
36
+ end
37
+ end
38
+
39
+ it 'does not affect non-money expressions' do
40
+ expect(1.00.to_i).to eql(1)
41
+ expect(100.to_s).to eql('100')
42
+ expect { 1.xxx_to_y }.to raise_error(NoMethodError)
43
+ end
44
+ end
45
+
46
+ context '#xxx_to (convert to multiple currencies)' do
47
+ it 'exchanges USD to JPY and EUR' do
48
+ ['jpy', 'eur'].each { |target| mock_google_currency_api('usd', target) }
49
+ expect(1.00.usd_to(:jpy, :eur)).to eql [100.31, 0.76]
50
+ end
51
+
52
+ it 'exchanges JPY to USD and EUR' do
53
+ ['usd', 'eur'].each { |target| mock_google_currency_api('jpy', target) }
54
+ expect(100.jpy_to(:usd, :eur)).to eql [1.0, 0.76]
55
+ end
56
+
57
+ it 'raise NoCurrencyDataError' do
58
+ ['usd', 'xxx'].each { |target| mock_google_currency_api('jpy', target) }
59
+ expect { 100.jpy_to(:usd, :xxx) }.to raise_error(nocurrency_error)
60
+ end
61
+ end
62
+ end
63
+
64
+ describe String do
65
+ let(:nocurrency_error) { MoneyExchange::Exchange::NoCurrencyDataError }
66
+
67
+ before(:each) do
68
+ FakeWeb.clean_registry
69
+ end
70
+
71
+ describe '#xxx_to_yyy' do
72
+ it 'exchanges base to target currency' do
73
+ mock_google_currency_api('usd', 'jpy')
74
+ expect('1.00'.usd_to_jpy).to eql(100.31)
75
+ mock_google_currency_api('jpy', 'usd')
76
+ expect('150'.jpy_to_usd).to eql(1.50)
77
+ mock_google_currency_api('eur', 'usd')
78
+ expect('1.23'.eur_to_usd).to eql(1.62)
79
+ end
80
+
81
+ it 'raise NoCurrencyDataError' do
82
+ mock_google_currency_api('jpy', 'xxx')
83
+ expect { '100'.jpy_to_xxx }.to raise_error(nocurrency_error)
84
+ end
85
+ end
86
+
87
+ context '#xxx_to (convert to multiple currencies)' do
88
+ it 'exchanges xxx to yyy and zzz' do
89
+ ['jpy', 'eur'].each { |target| mock_google_currency_api('usd', target) }
90
+ expect('1.00'.usd_to(:jpy, :eur)).to eql [100.31, 0.76]
91
+ ['usd', 'eur'].each { |target| mock_google_currency_api('jpy', target) }
92
+ expect('100'.jpy_to(:usd, :eur)).to eql [1.0, 0.76]
93
+ end
94
+
95
+ it 'raise NoCurrencyDataError' do
96
+ ['usd', 'xxx'].each { |target| mock_google_currency_api('jpy', target) }
97
+ expect { '100'.jpy_to(:usd, :xxx) }.to raise_error(nocurrency_error)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'money_exchange'
3
+
4
+ require "fakeweb"
5
+
6
+ module HelperMethods
7
+ def fixture(name)
8
+ File.read(File.dirname(__FILE__) + "/support/#{name}")
9
+ end
10
+
11
+ def mock_google_currency_api(base, target)
12
+ uri = "http://www\.google\.com/ig/calculator"
13
+ query = "?hl=en&q=1#{base}=?#{target}"
14
+
15
+ begin
16
+ response ||= fixture("rate_#{base}_to_#{target}.json")
17
+
18
+ FakeWeb.register_uri(:get, uri+query, :body => response)
19
+ rescue Errno::ENOENT
20
+ response = fixture("rate_error.json")
21
+ retry
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ RSpec.configuration.include(HelperMethods)
28
+
@@ -0,0 +1 @@
1
+ {lhs: "",rhs: "",error: "4",icc: false}
@@ -0,0 +1 @@
1
+ {lhs: "1 Euro",rhs: "131.818638 Japanese yen",error: "",icc: true}
@@ -0,0 +1 @@
1
+ {lhs: "1 Euro",rhs: "1.3141 U.S. dollars",error: "",icc: true}
@@ -0,0 +1 @@
1
+ {lhs: "1 Japanese yen",rhs: "0.00758618066 Euros",error: "",icc: true}
@@ -0,0 +1 @@
1
+ {lhs: "1 Japanese yen",rhs: "0.009969 U.S. dollars",error: "",icc: true}
@@ -0,0 +1 @@
1
+ {lhs: "1 U.S. dollar",rhs: "0.760977095 Euros",error: "",icc: true}
@@ -0,0 +1 @@
1
+ {lhs: "1 U.S. dollar",rhs: "100.310964 Japanese yen",error: "",icc: true}
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: money_exchange
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - kyoendo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeweb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Just another currency converter
84
+ email:
85
+ - postagie@gmail.com
86
+ executables:
87
+ - money_exchange
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .travis.yml
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/money_exchange
99
+ - lib/money_exchange.rb
100
+ - lib/money_exchange/command.rb
101
+ - lib/money_exchange/core_ext.rb
102
+ - lib/money_exchange/version.rb
103
+ - money_exchange.gemspec
104
+ - spec/money_exchange_command_spec.rb
105
+ - spec/money_exchange_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/rate_error.json
108
+ - spec/support/rate_eur_to_jpy.json
109
+ - spec/support/rate_eur_to_usd.json
110
+ - spec/support/rate_jpy_to_eur.json
111
+ - spec/support/rate_jpy_to_usd.json
112
+ - spec/support/rate_usd_to_eur.json
113
+ - spec/support/rate_usd_to_jpy.json
114
+ homepage: https://github.com/melborne/money_exchange
115
+ licenses:
116
+ - MIT
117
+ metadata: {}
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubyforge_project:
134
+ rubygems_version: 2.1.5
135
+ signing_key:
136
+ specification_version: 4
137
+ summary: Just another currency converter using Google currency converter API.
138
+ test_files:
139
+ - spec/money_exchange_command_spec.rb
140
+ - spec/money_exchange_spec.rb
141
+ - spec/spec_helper.rb
142
+ - spec/support/rate_error.json
143
+ - spec/support/rate_eur_to_jpy.json
144
+ - spec/support/rate_eur_to_usd.json
145
+ - spec/support/rate_jpy_to_eur.json
146
+ - spec/support/rate_jpy_to_usd.json
147
+ - spec/support/rate_usd_to_eur.json
148
+ - spec/support/rate_usd_to_jpy.json
149
+ has_rdoc: