dolarblue 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +4 -0
- data/.travis.yml +5 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +4 -0
- data/LICENSE.md +22 -0
- data/README.md +82 -0
- data/Rakefile +6 -0
- data/bin/dolarblue +4 -0
- data/dolarblue.gemspec +38 -0
- data/lib/dolarblue.rb +11 -0
- data/lib/dolarblue/class_methods.rb +11 -0
- data/lib/dolarblue/configuration.rb +48 -0
- data/lib/dolarblue/exchange.rb +108 -0
- data/lib/dolarblue/instance_methods.rb +73 -0
- data/lib/dolarblue/version.rb +3 -0
- data/spec/dolarblue_spec.rb +82 -0
- data/spec/exchange_spec.rb +92 -0
- data/spec/spec_helper.rb +22 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ad3f2ba7b746cca40311cb8fae901431406e47bd
|
4
|
+
data.tar.gz: 755868bf374ae639c8228d8bdb968ac6d7322bab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1ac8501dcf5a135914774e6f00e3ca4af2e67900a518388359743c0a58c476b2b4bb4f333aa78fc9999ec6c134f8e28d668c271c929b8d0d8774fd6e31c4b45
|
7
|
+
data.tar.gz: 99f48c75ff9a0e003d7df6a9e8eae9f645cb743898e697b7d48290f1691e0f9bc6dc3cff5e4fcd94605f8b69c511dce65119bea1f8e29de3a5d7ca502e7d735f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
## [In git](https://github.com/elgalu/dolarblue/compare/v0.0.1...HEAD)
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
* n/a
|
5
|
+
|
6
|
+
### Bugfixes
|
7
|
+
* n/a
|
8
|
+
|
9
|
+
### Chores
|
10
|
+
* n/a
|
11
|
+
|
12
|
+
## [v0.0.1](https://github.com/elgalu/dolarblue/tree/v0.0.1)
|
13
|
+
|
14
|
+
## First gem release
|
15
|
+
|
16
|
+
### Features:
|
17
|
+
* Query Argentine Peso vs US$ exchange values with particular interest in official vs. ilegal (blue) reference prices. (Leo Gallucci)
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Leo Gallucci
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Dolarblue
|
2
|
+
|
3
|
+
[![Gem Version][GV img]][Gem Version]
|
4
|
+
[![Build Status][BS img]][Build Status]
|
5
|
+
[![Dependency Status][DS img]][Dependency Status]
|
6
|
+
[![Code Climate][CC img]][Code Climate]
|
7
|
+
[![Coverage Status][CS img]][Coverage Status]
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
Query Argentine Peso vs US$ exchange values with particular interest in official vs. ilegal (blue) reference prices.
|
12
|
+
|
13
|
+
[dolarblue][RubyGems] is a command-line tool to query AR$ vs US$ exchange values.
|
14
|
+
|
15
|
+
The term [blue][] denotes an important difference between the [real value][] of Argentine local currency (the argentine peso) versus the official value currently unreacheable to the general public.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
`$ gem install dolarblue` or add to your [Gemfile][] this line: `gem 'dolarblue'` then run [bundle install][]
|
20
|
+
|
21
|
+
## Usage (command-line)
|
22
|
+
|
23
|
+
Query latest values
|
24
|
+
|
25
|
+
$ dolarblue
|
26
|
+
|
27
|
+
Sample result:
|
28
|
+
|
29
|
+
Obtaining latest AR$ vs US$ exchange values...Done.
|
30
|
+
|
31
|
+
- Official: 5.01 / 5.06 (Updated 48 minutes and 43 seconds ago)
|
32
|
+
- Blue....: 7.74 / 7.82 (Updated 4 hours and 27 minutes ago)
|
33
|
+
- Gap.....: 55%
|
34
|
+
|
35
|
+
Information sources:
|
36
|
+
Official: https://twitter.com/cotizacionhoyar/status/309381355450560512
|
37
|
+
Blue....: https://twitter.com/DolarBlue/status/309326405148233731
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
1. Fork it.
|
42
|
+
2. Make your feature addition or bug fix and create your feature branch.
|
43
|
+
3. Update the [Change Log][].
|
44
|
+
3. Add specs/tests for it. This is important so I don't break it in a future version unintentionally.
|
45
|
+
4. Commit, create a new Pull Request.
|
46
|
+
5. Check that your pull request passes the [build][travis pull requests].
|
47
|
+
|
48
|
+
## License
|
49
|
+
|
50
|
+
Released under the MIT License. See the [LICENSE][] file for further details.
|
51
|
+
|
52
|
+
## Links
|
53
|
+
|
54
|
+
[RubyGems][] | [Documentation][] | [Source][] | [Bugtracker][] | [Build Status][] | [Dependency Status][] | [Code Climate][]
|
55
|
+
|
56
|
+
|
57
|
+
[bundle install]: http://gembundler.com/man/bundle-install.1.html
|
58
|
+
[Gemfile]: http://gembundler.com/man/gemfile.5.html
|
59
|
+
[LICENSE]: LICENSE.md
|
60
|
+
[Change Log]: CHANGELOG.md
|
61
|
+
|
62
|
+
[RubyGems]: https://rubygems.org/gems/dolarblue
|
63
|
+
[Documentation]: http://rubydoc.info/gems/dolarblue
|
64
|
+
[Source]: https://github.com/elgalu/dolarblue
|
65
|
+
[Bugtracker]: https://github.com/elgalu/dolarblue/issues
|
66
|
+
|
67
|
+
[travis pull requests]: https://travis-ci.org/elgalu/dolarblue/pull_requests
|
68
|
+
|
69
|
+
[Gem Version]: https://rubygems.org/gems/dolarblue
|
70
|
+
[Build Status]: https://travis-ci.org/elgalu/dolarblue
|
71
|
+
[Dependency Status]: https://gemnasium.com/elgalu/dolarblue
|
72
|
+
[Code Climate]: https://codeclimate.com/github/elgalu/dolarblue
|
73
|
+
[Coverage Status]: https://coveralls.io/r/elgalu/dolarblue
|
74
|
+
|
75
|
+
[GV img]: https://badge.fury.io/rb/dolarblue.png
|
76
|
+
[BS img]: https://travis-ci.org/elgalu/dolarblue.png
|
77
|
+
[DS img]: https://gemnasium.com/elgalu/dolarblue.png
|
78
|
+
[CC img]: https://codeclimate.com/github/elgalu/dolarblue.png
|
79
|
+
[CS img]: https://coveralls.io/repos/elgalu/dolarblue/badge.png?branch=master
|
80
|
+
|
81
|
+
[blue]: http://latino.foxnews.com/latino/news/2012/05/19/argentina-currency-black-market-expands/
|
82
|
+
[real value]: http://www.buenosairesherald.com/tags/dollar
|
data/Rakefile
ADDED
data/bin/dolarblue
ADDED
data/dolarblue.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'dolarblue/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
|
7
|
+
spec.platform = Gem::Platform::RUBY
|
8
|
+
spec.name = "dolarblue"
|
9
|
+
spec.version = Dolarblue::VERSION
|
10
|
+
spec.summary = %q{Query Argentine Peso vs US$ exchange values with particular interest in official vs. ilegal (blue) reference prices.}
|
11
|
+
spec.description = spec.summary
|
12
|
+
|
13
|
+
spec.required_ruby_version = '>= 2.0.0'
|
14
|
+
spec.required_rubygems_version = '>= 2'
|
15
|
+
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.authors = ["Leo Gallucci"]
|
19
|
+
spec.email = ["elgalu3@gmail.com"]
|
20
|
+
spec.homepage = "https://github.com/elgalu/dolarblue"
|
21
|
+
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
spec.files = `git ls-files`.split($/)
|
24
|
+
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
25
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
|
+
|
27
|
+
spec.add_runtime_dependency "twitter_anonymous_client", ">= 1.0.2.0"
|
28
|
+
spec.add_runtime_dependency "time_ago_in_words", ">= 0.1.0"
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", ">= 1.2"
|
31
|
+
spec.add_development_dependency "rake"
|
32
|
+
spec.add_development_dependency "rspec", "~> 2.13"
|
33
|
+
spec.add_development_dependency "redcarpet", ">= 2.2"
|
34
|
+
spec.add_development_dependency "yard", ">= 0.8.5.2"
|
35
|
+
spec.add_development_dependency "simplecov", ">= 0.7.1"
|
36
|
+
spec.add_development_dependency 'coveralls', '>= 0.5.8'
|
37
|
+
|
38
|
+
end
|
data/lib/dolarblue.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'dolarblue/version'
|
2
|
+
require 'dolarblue/configuration'
|
3
|
+
require 'dolarblue/class_methods'
|
4
|
+
require 'dolarblue/instance_methods'
|
5
|
+
require 'dolarblue/exchange'
|
6
|
+
|
7
|
+
# Main class used as builder and also as Dolarblue namespace
|
8
|
+
class Dolarblue
|
9
|
+
extend ClassMethods
|
10
|
+
include InstanceMethods
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Dolarblue
|
2
|
+
module ClassMethods
|
3
|
+
# Returns all the dollar exchange 'Blue' vs 'Official' values and percentiles
|
4
|
+
# suitable for user printing
|
5
|
+
#
|
6
|
+
# @return [String] with all dollar exchange 'Blue' vs 'Official' values
|
7
|
+
def get_output
|
8
|
+
new.update!.output
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class Dolarblue
|
4
|
+
|
5
|
+
# Singleton configuration class
|
6
|
+
class Configuration
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# Default gap factor between the sale value vs. the buy value
|
10
|
+
# Usually 1%
|
11
|
+
#
|
12
|
+
# @return [Float] the percentile between 0..1
|
13
|
+
def buy_sell_factor
|
14
|
+
Float(0.99)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Twitter screen name for the `blue` dollar value
|
18
|
+
#
|
19
|
+
# @return [String] the twitter screen name for the `blue` dollar value
|
20
|
+
def blue_screen_name
|
21
|
+
'DolarBlue'
|
22
|
+
end
|
23
|
+
|
24
|
+
# Regular expression to be used to match the Tweet text for `blue` value
|
25
|
+
# In order to extract the integer value from $1 and the decimal value from $2
|
26
|
+
#
|
27
|
+
# @return [Regexp] the regular expression to be used to match the Tweet text for `blue` value
|
28
|
+
def blue_regexp
|
29
|
+
/\$(\d+)[\.,](\d+)/
|
30
|
+
end
|
31
|
+
|
32
|
+
# Twitter screen name for the official (legal) dollar value
|
33
|
+
#
|
34
|
+
# @return [String] the twitter screen name for the official (legal) dollar value
|
35
|
+
def official_screen_name
|
36
|
+
'cotizacionhoyar'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Regular expression to be used to match the Tweet text for official value
|
40
|
+
# In order to extract the integer value from $1 and the decimal value from $2
|
41
|
+
#
|
42
|
+
# @return [Regexp] the regular expression to be used to match the Tweet text for official value
|
43
|
+
def official_regexp
|
44
|
+
/[Dd]olar: (\d+)[\.,](\d+)/
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'twitter_anonymous_client'
|
2
|
+
require 'time_ago_in_words'
|
3
|
+
|
4
|
+
class Dolarblue
|
5
|
+
|
6
|
+
# Used to build dollar exchange value object
|
7
|
+
class Exchange
|
8
|
+
attr_reader :name, :source_url, :updated_at
|
9
|
+
|
10
|
+
# Create a new dollar exchange value instance
|
11
|
+
#
|
12
|
+
# @param [String] name the name of the object
|
13
|
+
# actual values are 'Blue' and 'Official'
|
14
|
+
# @param [String] screen_name the twitter screen_name from which to retrieve the values
|
15
|
+
# @param [Regexp] regexp the regular expressions to be used to parse the dollar values from the tweet text
|
16
|
+
# @param [Float] buy_sell_factor the factor to multiply sale value in order to get buy value
|
17
|
+
# difference is usually 1% so a factor of 0.99 would apply to get that
|
18
|
+
#
|
19
|
+
# @return [self]
|
20
|
+
#
|
21
|
+
# @note Using ruby 2 feature: Keyworded Arguments
|
22
|
+
def initialize(name: nil, screen_name: nil, regexp: nil, buy_sell_factor: nil)
|
23
|
+
fail ArgumentError, "name, screen_name, regexp and buy_sell_factor are all required" unless name && screen_name && regexp && buy_sell_factor
|
24
|
+
@name = name
|
25
|
+
@screen_name = screen_name
|
26
|
+
@regexp = regexp
|
27
|
+
@buy_sell_factor = buy_sell_factor
|
28
|
+
@sell_value = nil
|
29
|
+
@source_url = nil
|
30
|
+
@updated_at = nil
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Buy (lowest) dollar exchange value
|
35
|
+
# usually obtained from sell value multiplied by sell factor
|
36
|
+
#
|
37
|
+
# @return [Float] lowest dollar exchange value
|
38
|
+
def buy_value
|
39
|
+
ensure_valid
|
40
|
+
(@sell_value * @buy_sell_factor).round(2)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sell (highest) dollar exchange value
|
44
|
+
# usually obtained directly from the source
|
45
|
+
#
|
46
|
+
# @return [Float] highest dollar exchange value
|
47
|
+
def sell_value
|
48
|
+
ensure_valid
|
49
|
+
@sell_value.round(2)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns valid state
|
53
|
+
#
|
54
|
+
# @return [true, false] valid boolean state
|
55
|
+
def valid?
|
56
|
+
@sell_value && @sell_value.kind_of?(Numeric) && @sell_value > 0
|
57
|
+
end
|
58
|
+
|
59
|
+
# Connect to the source and retrieve dollar exchange value
|
60
|
+
#
|
61
|
+
# @return [self]
|
62
|
+
def update!
|
63
|
+
tweet = Twitter::Client.new.last_tweet(@screen_name)
|
64
|
+
fail "Couldn't obtain value out of #{tweet.text}" unless tweet.text =~ @regexp
|
65
|
+
@sell_value = Float("#{$1}.#{$2}")
|
66
|
+
@updated_at = tweet.created_at
|
67
|
+
@source_url = tweet.status_url
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the last updated time from now humanized in English words
|
72
|
+
#
|
73
|
+
# @return [String] humanized ago date in English
|
74
|
+
def updated_ago
|
75
|
+
ensure_valid
|
76
|
+
@updated_at.to_time.ago_in_words
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return a string suitable for user output about exchange values
|
80
|
+
#
|
81
|
+
# @return [String] output exchange values 1 line string
|
82
|
+
def output_values
|
83
|
+
ensure_valid
|
84
|
+
dots = '.' * (8 - name.size).abs
|
85
|
+
"- #{name}#{dots}: #{buy_value} / #{sell_value} (Updated #{updated_ago})"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return a string suitable for user output with the link to the sources
|
89
|
+
#
|
90
|
+
# @return [String] output links with sources from which the values where obtained
|
91
|
+
def output_link
|
92
|
+
ensure_valid
|
93
|
+
dots = '.' * (8 - name.size).abs
|
94
|
+
"#{name}#{dots}: #{source_url}"
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Ensure object is valid before continuing with certain operations
|
100
|
+
# like getting output strings or last updated date
|
101
|
+
#
|
102
|
+
# @private
|
103
|
+
def ensure_valid
|
104
|
+
fail "Call update! first" unless valid?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Dolarblue
|
2
|
+
module InstanceMethods
|
3
|
+
|
4
|
+
# Create a new Dolarblue instance to work later on
|
5
|
+
#
|
6
|
+
# @param [Configuration] config the configuration instance
|
7
|
+
#
|
8
|
+
# @return [Dolarblue] new instance
|
9
|
+
def initialize(config = Configuration.instance)
|
10
|
+
fail ArgumentError, "Expected a Dolarblue::Configuration instance as argument" unless config.is_a?(Configuration)
|
11
|
+
@blue = Dolarblue::Exchange.new(
|
12
|
+
name: 'Blue',
|
13
|
+
screen_name: config.blue_screen_name,
|
14
|
+
regexp: config.blue_regexp,
|
15
|
+
buy_sell_factor: config.buy_sell_factor)
|
16
|
+
@official = Dolarblue::Exchange.new(
|
17
|
+
name: 'Official',
|
18
|
+
screen_name: config.official_screen_name,
|
19
|
+
regexp: config.official_regexp,
|
20
|
+
buy_sell_factor: config.buy_sell_factor)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns current object state, whether valid or not
|
25
|
+
#
|
26
|
+
# @return [true, false] boolean state
|
27
|
+
def valid?
|
28
|
+
@blue.valid? && @official.valid?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Connect to the source and retrieve dollar exchange values
|
32
|
+
#
|
33
|
+
# @return [self]
|
34
|
+
def update!
|
35
|
+
print "Obtaining latest AR$ vs US$ exchange values..."
|
36
|
+
@blue.update!
|
37
|
+
@official.update!
|
38
|
+
print "Done.\n\n"
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the gap between the real (blue) dollar value versus the official
|
43
|
+
#
|
44
|
+
# @return [Float] percentile value between 0..1
|
45
|
+
def gap
|
46
|
+
fail "Need blue and official values to be setup before calculating the gap" unless @blue.sell_value && @blue.sell_value > 0 && @official.sell_value && @official.sell_value > 0
|
47
|
+
(@blue.sell_value / @official.sell_value - 1)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the gap percentile between the real (blue) dollar value versus the official
|
51
|
+
#
|
52
|
+
# @return [Float] percentile value between 0..100
|
53
|
+
def gap_percent
|
54
|
+
(gap * 100).round(0)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Output string to be used by the binary `dolarblue`
|
58
|
+
#
|
59
|
+
# @return [String] the output with dollar exchange information
|
60
|
+
def output
|
61
|
+
<<-OUTPUT
|
62
|
+
#{@official.output_values}
|
63
|
+
#{@blue.output_values}
|
64
|
+
- Gap.....: #{gap_percent}%
|
65
|
+
|
66
|
+
Information sources:
|
67
|
+
#{@official.output_link}
|
68
|
+
#{@blue.output_link}
|
69
|
+
OUTPUT
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dolarblue do
|
4
|
+
let(:blue_tweet) do
|
5
|
+
Twitter::Tweet.new({
|
6
|
+
id: '309326405148233731',
|
7
|
+
text: 'Dolar Paralelo: $7,82',
|
8
|
+
created_at: DateTime.parse('2013-03-06T12:35:36-03:00'),
|
9
|
+
screen_name: 'DolarBlue'
|
10
|
+
})
|
11
|
+
end
|
12
|
+
let(:official_tweet) do
|
13
|
+
Twitter::Tweet.new({
|
14
|
+
id: '309289043722637312',
|
15
|
+
text: '#Cotizacion cierre promedio parcial 06-03-13: #Dolar: 5.06 // #Euro: 6.71 // #Real: 2.74.',
|
16
|
+
created_at: DateTime.parse('2013-03-06T10:07:08-03:00'),
|
17
|
+
screen_name: 'cotizacionhoyar'
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
before do
|
22
|
+
Twitter::Client.stub_chain(:new, :last_tweet).with('DolarBlue').and_return(blue_tweet)
|
23
|
+
Twitter::Client.stub_chain(:new, :last_tweet).with('cotizacionhoyar').and_return(official_tweet)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#new' do
|
27
|
+
it 'fails if argument is not a Configuration class' do
|
28
|
+
expect { described_class.new(nil) }.to raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'start as invalid right after creation' do
|
32
|
+
subject.should_not be_valid
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'fails if you try to use it before is valid' do
|
36
|
+
expect { subject.gap }.to raise_error
|
37
|
+
expect { subject.gap_percent }.to raise_error
|
38
|
+
expect { subject.output }.to raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'updated' do
|
43
|
+
before do
|
44
|
+
subject.update!
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#update!' do
|
48
|
+
it 'becomes valid after calling update!' do
|
49
|
+
subject.should be_valid
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#output' do
|
54
|
+
it 'has an output with real values' do
|
55
|
+
subject.output.should match(/Blue/)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'gap values' do
|
60
|
+
it 'has a valid gap value' do
|
61
|
+
subject.gap.should be >= 0
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has a valid gap % value' do
|
65
|
+
subject.gap_percent.should be >= 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'constants' do
|
71
|
+
it 'should have a version number' do
|
72
|
+
Dolarblue::VERSION.should_not be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'ClassMethods' do
|
77
|
+
it 'has an get_output() class method to retrieve latest values' do
|
78
|
+
Dolarblue.get_output.should match(/Blue/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dolarblue::Exchange do
|
4
|
+
let(:screen_name) { 'DolarBlue' }
|
5
|
+
let(:blue) { described_class.new(name: 'Blue', screen_name: screen_name, regexp: /\$(\d+)[\.,](\d+)/, buy_sell_factor: 0.99) }
|
6
|
+
let(:blue_tweet) do
|
7
|
+
Twitter::Tweet.new({
|
8
|
+
id: '309326405148233731',
|
9
|
+
text: 'Dolar Paralelo: $7,82',
|
10
|
+
created_at: DateTime.parse('2013-03-06T12:35:36-03:00'),
|
11
|
+
screen_name: 'DolarBlue'
|
12
|
+
})
|
13
|
+
end
|
14
|
+
let(:official_tweet) do
|
15
|
+
Twitter::Tweet.new({
|
16
|
+
id: '309289043722637312',
|
17
|
+
text: '#Cotizacion cierre promedio parcial 06-03-13: #Dolar: 5.06 // #Euro: 6.71 // #Real: 2.74.',
|
18
|
+
created_at: DateTime.parse('2013-03-06T10:07:08-03:00'),
|
19
|
+
screen_name: 'cotizacionhoyar'
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
Twitter::Client.stub_chain(:new, :last_tweet).with(screen_name).and_return(blue_tweet)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#new' do
|
28
|
+
it 'fails if missing arguments' do
|
29
|
+
expect { described_class.new(nil) }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'start as invalid right after creation' do
|
33
|
+
blue.should_not be_valid
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'validation' do
|
38
|
+
it 'fails if you try to use it before is valid' do
|
39
|
+
expect { blue.buy_value }.to raise_error
|
40
|
+
expect { blue.sell_value }.to raise_error
|
41
|
+
expect { blue.updated_ago }.to raise_error
|
42
|
+
expect { blue.output_values }.to raise_error
|
43
|
+
expect { blue.output_link }.to raise_error
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'updated' do
|
48
|
+
before do
|
49
|
+
blue.update!
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#update!' do
|
53
|
+
it 'becomes valid after calling update!' do
|
54
|
+
blue.should be_valid
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'instance methods' do
|
59
|
+
it 'has the correct name' do
|
60
|
+
blue.name.should == 'Blue'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'has a proper buy_value' do
|
64
|
+
blue.buy_value.should be > 0
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'has a proper sell_value' do
|
68
|
+
blue.sell_value.should be > 0
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'has a proper updated_at' do
|
72
|
+
blue.updated_at.should be_a(DateTime)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'has a proper updated_ago' do
|
76
|
+
blue.updated_ago.should be_a(String)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'has a source url' do
|
80
|
+
blue.source_url.should be_a(String)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'has a valid output values string' do
|
84
|
+
blue.output_values.should match(/Blue.*Updated/)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'has a valid output link string' do
|
88
|
+
blue.output_link.should match(/Blue.*http.*twitter/)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
SimpleCov.start
|
9
|
+
|
10
|
+
# Internal
|
11
|
+
require 'dolarblue'
|
12
|
+
|
13
|
+
# Require this file using `require "spec_helper"` within each of your specs
|
14
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
17
|
+
config.run_all_when_everything_filtered = true
|
18
|
+
config.filter_run :focus
|
19
|
+
|
20
|
+
# Run specs in random order to surface order dependencies.
|
21
|
+
config.order = 'random'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dolarblue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leo Gallucci
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: twitter_anonymous_client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: time_ago_in_words
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
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: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.13'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: redcarpet
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.8.5.2
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.8.5.2
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.7.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.7.1
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: coveralls
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.5.8
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.5.8
|
139
|
+
description: Query Argentine Peso vs US$ exchange values with particular interest
|
140
|
+
in official vs. ilegal (blue) reference prices.
|
141
|
+
email:
|
142
|
+
- elgalu3@gmail.com
|
143
|
+
executables:
|
144
|
+
- dolarblue
|
145
|
+
extensions: []
|
146
|
+
extra_rdoc_files: []
|
147
|
+
files:
|
148
|
+
- .gitignore
|
149
|
+
- .rspec
|
150
|
+
- .travis.yml
|
151
|
+
- .yardopts
|
152
|
+
- CHANGELOG.md
|
153
|
+
- Gemfile
|
154
|
+
- LICENSE.md
|
155
|
+
- README.md
|
156
|
+
- Rakefile
|
157
|
+
- bin/dolarblue
|
158
|
+
- dolarblue.gemspec
|
159
|
+
- lib/dolarblue.rb
|
160
|
+
- lib/dolarblue/class_methods.rb
|
161
|
+
- lib/dolarblue/configuration.rb
|
162
|
+
- lib/dolarblue/exchange.rb
|
163
|
+
- lib/dolarblue/instance_methods.rb
|
164
|
+
- lib/dolarblue/version.rb
|
165
|
+
- spec/dolarblue_spec.rb
|
166
|
+
- spec/exchange_spec.rb
|
167
|
+
- spec/spec_helper.rb
|
168
|
+
homepage: https://github.com/elgalu/dolarblue
|
169
|
+
licenses:
|
170
|
+
- MIT
|
171
|
+
metadata: {}
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.0.0
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - '>='
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '2'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project:
|
188
|
+
rubygems_version: 2.0.0
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: Query Argentine Peso vs US$ exchange values with particular interest in official
|
192
|
+
vs. ilegal (blue) reference prices.
|
193
|
+
test_files:
|
194
|
+
- spec/dolarblue_spec.rb
|
195
|
+
- spec/exchange_spec.rb
|
196
|
+
- spec/spec_helper.rb
|
197
|
+
has_rdoc:
|