oanda_api 0.9.0 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -3
- data/Gemfile +9 -5
- data/README.md +3 -1
- data/lib/oanda_api.rb +2 -0
- data/lib/oanda_api/client/client.rb +4 -0
- data/lib/oanda_api/client/json_parser.rb +16 -0
- data/lib/oanda_api/resource/candle.rb +45 -0
- data/lib/oanda_api/resource_base.rb +2 -2
- data/lib/oanda_api/streaming/adapter_error.rb +19 -0
- data/lib/oanda_api/streaming/adapters/generic.rb +29 -0
- data/lib/oanda_api/streaming/adapters/gson.rb +31 -0
- data/lib/oanda_api/streaming/adapters/yajl.rb +31 -0
- data/lib/oanda_api/streaming/client.rb +1 -1
- data/lib/oanda_api/streaming/json_parser.rb +125 -0
- data/lib/oanda_api/streaming/request.rb +29 -24
- data/lib/oanda_api/version.rb +1 -1
- data/oanda_api.gemspec +3 -3
- data/spec/oanda_api/client/json_parser_spec.rb +13 -0
- data/spec/oanda_api/resource_base_spec.rb +6 -0
- data/spec/oanda_api/streaming/adapters/generic_spec.rb +7 -0
- data/spec/oanda_api/streaming/adapters/gson_spec.rb +7 -0
- data/spec/oanda_api/streaming/adapters/yajl_spec.rb +7 -0
- data/spec/oanda_api/streaming/json_parser_spec.rb +65 -0
- data/spec/oanda_api/streaming/request_spec.rb +29 -1
- data/spec/shared/adapter.rb +19 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/support/vcr.rb +1 -0
- metadata +28 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f7f97bda3c0ece6ba2dfbabf7b59cab04991de0
|
4
|
+
data.tar.gz: efcdee86eeca8013b772aac230a5a33476051b12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27f14d9b88d7a01908c566ed116bea03c60079a7807ae5449224baabb511ab1ffea8924c6da67aaa47e94253eea5f400cbbac48582897a2f34e2c43392c6e797
|
7
|
+
data.tar.gz: 4dea06ea3ca3763503b44370b14b9adcd2b618a6fc6f6b28cd2ac6d85ed779cb9b8314f198b896eb80434028f81bc912d1dab8f57d74df53f86420f3e467c922
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,29 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 0.9.0
|
4
4
|
|
5
5
|
* Add support for live [Streaming](http://developer.oanda.com/rest-live/streaming/).
|
6
6
|
* Add #to_json serialization to resource classes.
|
7
|
-
*
|
7
|
+
* Fixed Yardoc formatting.
|
8
8
|
|
9
9
|
###What's New?
|
10
10
|
OandaAPI now supports Oanda's streaming API for consuming realtime ticks and account transactions. See the example in the README and have a look at the specs for `OandaAPI::Streaming::Client`.
|
11
|
-
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## 0.9.1
|
15
|
+
|
16
|
+
* Fixed JSON serialization for nested ResourceBase instances.
|
17
|
+
* Fixed some edge cases that could generate ParseError when parsing streaming JSON.
|
18
|
+
* Added support for streaming JSON parsers [yajl-ruby](https://github.com/brianmario/yajl-ruby) and [gson](https://github.com/avsej/gson.rb).
|
19
|
+
* Serialized JSON is now deserialized using symbolized names to avoid garbage collection overhead that occurs when strings are used.
|
20
|
+
|
21
|
+
###What's New?
|
22
|
+
As with version 0.9.0, `OandaAPI::Streaming::Client` will use the JSON gem parser if it is the only JSON parser installed. However, the JSON gem does not support parsing streams of objects very robustly (i.e. it expects complete documents, or the stream to delimit multiple objects consistently). If you are using the streaming API, and install either the [yajl-ruby](https://github.com/brianmario/yajl-ruby) gem (for MRI and Rubinius ruby) or the [gson](https://github.com/avsej/gson.rb) gem (for jruby), then `OandaAPI::Streaming::Client` will use either of those streaming JSON gems for a gain in reliability.
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
## 0.9.2
|
27
|
+
|
28
|
+
* Specify version of HTTParty as 0.13.3 until HTTParty issue #398 is resolved.
|
29
|
+
* Now support any whitespace as delimiting multiple JSON objects in streaming API with `OandaAPI::Streaming::Adapters::Generic`.
|
data/Gemfile
CHANGED
@@ -4,15 +4,19 @@ gemspec
|
|
4
4
|
|
5
5
|
group :development do
|
6
6
|
gem "pry"
|
7
|
-
gem
|
8
|
-
gem
|
9
|
-
|
7
|
+
gem "pry-stack_explorer"
|
8
|
+
gem "pry-byebug"
|
10
9
|
gem "guard"
|
11
10
|
gem "guard-rspec"
|
12
11
|
gem "fuubar"
|
13
12
|
gem "redcarpet"
|
14
13
|
gem "github-markup"
|
15
|
-
gem "rubocop", require
|
14
|
+
gem "rubocop", :require => false
|
16
15
|
end
|
17
16
|
|
18
|
-
|
17
|
+
group :test do
|
18
|
+
gem "simplecov", :require => false
|
19
|
+
gem "codeclimate-test-reporter", :group => :test, :require => nil
|
20
|
+
# gem "yajl-ruby" # install this if you're running under mri or rubinius
|
21
|
+
# gem "gson" # install this if you're running under jruby
|
22
|
+
end
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# OandaAPI
|
2
|
+
[![Code Climate](https://codeclimate.com/github/nukeproof/oanda_api/badges/gpa.svg)](https://codeclimate.com/github/nukeproof/oanda_api) [![Test Coverage](https://codeclimate.com/github/nukeproof/oanda_api/badges/coverage.svg)](https://codeclimate.com/github/nukeproof/oanda_api)
|
3
|
+
|
2
4
|
Access Oanda FX accounts, get market data, trade, build trading strategies using Ruby.
|
3
5
|
## Synopsis
|
4
6
|
OandaAPI is a simple Ruby wrapper for the [Oanda REST API](http://developer.oanda.com/rest-live/introduction/).
|
@@ -128,7 +130,7 @@ client = OandaAPI::Streaming::Client.new(:practice, ENV.fetch("OANDA_PRACTICE_TO
|
|
128
130
|
prices = client.prices(account_id: 1234, instruments: %w[AUD_CAD AUD_CHF])
|
129
131
|
prices.stream do |price|
|
130
132
|
# Note: The code in this block should handle the price
|
131
|
-
# as
|
133
|
+
# as efficiently as possible, otherwise the connection could timeout.
|
132
134
|
# For example, you could publish the tick on a queue to be handled
|
133
135
|
# by some other thread or process.
|
134
136
|
price # => OandaAPI::Resource::Price
|
data/lib/oanda_api.rb
CHANGED
@@ -3,6 +3,7 @@ require 'httparty'
|
|
3
3
|
require 'persistent_httparty'
|
4
4
|
require 'http/exceptions'
|
5
5
|
require 'time'
|
6
|
+
require 'erb' # Hack to fix issue with httparty 0.13.4 [issue 398](https://github.com/jnunemaker/httparty/issues/398)
|
6
7
|
|
7
8
|
require_relative 'oanda_api/configuration'
|
8
9
|
require_relative 'oanda_api/client/client'
|
@@ -11,6 +12,7 @@ require_relative 'oanda_api/client/resource_descriptor'
|
|
11
12
|
require_relative 'oanda_api/client/token_client'
|
12
13
|
require_relative 'oanda_api/client/username_client'
|
13
14
|
require_relative 'oanda_api/streaming/client'
|
15
|
+
require_relative 'oanda_api/streaming/json_parser'
|
14
16
|
require_relative 'oanda_api/streaming/request'
|
15
17
|
require_relative 'oanda_api/errors'
|
16
18
|
require_relative 'oanda_api/resource_base'
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'httparty'
|
2
2
|
require 'http/exceptions'
|
3
|
+
require_relative 'json_parser'
|
3
4
|
|
4
5
|
module OandaAPI
|
5
6
|
# List of valid subdomains clients can access.
|
@@ -17,6 +18,9 @@ module OandaAPI
|
|
17
18
|
keep_alive: 30,
|
18
19
|
pool_size: 2
|
19
20
|
|
21
|
+
# Use a custom JSON parser
|
22
|
+
parser OandaAPI::Client::JsonParser
|
23
|
+
|
20
24
|
# Resource URI templates
|
21
25
|
BASE_URI = {
|
22
26
|
live: "https://api-fxtrade.oanda.com/[API_VERSION]",
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module OandaAPI
|
2
|
+
module Client
|
3
|
+
#
|
4
|
+
# Overrides the default JSON parser to symbolize names.
|
5
|
+
class JsonParser < HTTParty::Parser
|
6
|
+
SupportedFormats = {"application/json" => :json}
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# perform json parsing on body
|
11
|
+
def json
|
12
|
+
JSON.parse body, symbolize_names: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,6 +3,51 @@ module OandaAPI
|
|
3
3
|
# Candle value object.
|
4
4
|
# See the Oanda Developer Guide for information about {http://developer.oanda.com/rest-live/rates/#retrieveInstrumentHistory Candles}.
|
5
5
|
class Candle < ResourceBase
|
6
|
+
|
7
|
+
# Granularity Constants
|
8
|
+
# See http://developer.oanda.com/rest-live/rates/#aboutCandlestickRepresentation
|
9
|
+
module Granularity
|
10
|
+
# Top of minute alignments
|
11
|
+
S5 = "S5"
|
12
|
+
S10 = "S10"
|
13
|
+
S15 = "S15"
|
14
|
+
S30 = "S30"
|
15
|
+
M1 = "M1"
|
16
|
+
|
17
|
+
# Top of hour alignments
|
18
|
+
M2 = "M2"
|
19
|
+
M3 = "M3"
|
20
|
+
M4 = "M4"
|
21
|
+
M5 = "M5"
|
22
|
+
M10 = "M10"
|
23
|
+
M15 = "M15"
|
24
|
+
M30 = "M30"
|
25
|
+
H1 = "H1"
|
26
|
+
|
27
|
+
# Start of day alignments (default 17:00, Timezone/New York)
|
28
|
+
H2 = "H2"
|
29
|
+
H3 = "H3"
|
30
|
+
H4 = "H4"
|
31
|
+
H6 = "H6"
|
32
|
+
H8 = "H8"
|
33
|
+
H12 = "H12"
|
34
|
+
D = "D1"
|
35
|
+
|
36
|
+
# Start of week alignment (default Friday)
|
37
|
+
W = "W"
|
38
|
+
|
39
|
+
# Start of month alignment (first day of month)
|
40
|
+
M = "M"
|
41
|
+
|
42
|
+
VALID_GRANULARITIES = [S5,S10,S15,S30,M1,M2,M3,M4,M5,M10,M15,M30,H1,H2,H3,H4,H6,H8,H12,D,W,M]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Candle Formats
|
46
|
+
module Format
|
47
|
+
BIDASK = "bidask"
|
48
|
+
MIDPOINT = "midpoint"
|
49
|
+
end
|
50
|
+
|
6
51
|
attr_accessor :close_ask,
|
7
52
|
:close_bid,
|
8
53
|
:close_mid,
|
@@ -22,8 +22,8 @@ module OandaAPI
|
|
22
22
|
|
23
23
|
# Serializes an instance as JSON
|
24
24
|
# @return [String] a stringified JSON representation of an instance
|
25
|
-
def to_json
|
26
|
-
JSON.generate @_attributes.merge(custom_attributes)
|
25
|
+
def to_json(*args)
|
26
|
+
JSON.generate @_attributes.merge(custom_attributes), *args
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OandaAPI
|
2
|
+
module Streaming
|
3
|
+
#
|
4
|
+
# Raised if an invalid adapter is used with {OandaAPI::Streaming::JsonParser}
|
5
|
+
class AdapterError < ArgumentError
|
6
|
+
attr_reader :cause
|
7
|
+
|
8
|
+
def self.build(original_exception)
|
9
|
+
message = "Did not recognize your adapter specification (#{original_exception.message})."
|
10
|
+
new(message).tap do |exception|
|
11
|
+
exception.instance_eval do
|
12
|
+
@cause = original_exception
|
13
|
+
set_backtrace original_exception.backtrace
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module OandaAPI
|
2
|
+
module Streaming
|
3
|
+
#
|
4
|
+
# Everything related to `Streaming::Adapters`
|
5
|
+
module Adapters
|
6
|
+
#
|
7
|
+
# Uses the JSON library. This parser does not handle multiple json objects in a json stream
|
8
|
+
# unless the objects are separated with whitespace.
|
9
|
+
module Generic
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# A delimiter for separating multiple json objects in a stream.
|
13
|
+
DELIMITER = "<oanda_api::delimiter>"
|
14
|
+
MULTI_OBJECT_DELIMITER = "}#{DELIMITER}{"
|
15
|
+
|
16
|
+
# Deserializes a stream of JSON objects.
|
17
|
+
# @param [String] string serialized json.
|
18
|
+
# @return [Array<Hash>] an array of hashes.
|
19
|
+
def parse(string)
|
20
|
+
string.strip!
|
21
|
+
return [] if string.empty?
|
22
|
+
string.gsub(/}\s*{/, MULTI_OBJECT_DELIMITER).split(DELIMITER).map do |json|
|
23
|
+
JSON.parse json, symbolize_names: true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'gson'
|
2
|
+
|
3
|
+
module OandaAPI
|
4
|
+
module Streaming
|
5
|
+
module Adapters
|
6
|
+
#
|
7
|
+
# Can be used if the ruby engine (`RUBY_ENGINE`) is jruby. Uses the {https://github.com/avsej/gson.rb gson} gem.
|
8
|
+
# Handles streams of multiple JSON objects that may or may not be delimited with whitespace.
|
9
|
+
module Gson
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# Deserializes a stream of JSON objects.
|
13
|
+
# @param [String] string serialized json.
|
14
|
+
# @return [Array<Hash>] an array of hashes.
|
15
|
+
def parse(string)
|
16
|
+
string.strip!
|
17
|
+
return [] if string.empty?
|
18
|
+
[parser.decode(string)].flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @private
|
24
|
+
# Memoized parser instance.
|
25
|
+
def parser
|
26
|
+
@parser ||= ::Gson::Decoder.new(symbolize_keys: true)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'yajl'
|
2
|
+
|
3
|
+
module OandaAPI
|
4
|
+
module Streaming
|
5
|
+
module Adapters
|
6
|
+
#
|
7
|
+
# Can be used if the ruby engine (`RUBY_ENGINE`) is NOT jruby. Uses the {https://github.com/brianmario/yajl-ruby yajl-ruby} gem.
|
8
|
+
# Handles streams of multiple JSON objects that may or may not be delimited with whitespace.
|
9
|
+
module Yajl
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# Deserializes a stream of JSON objects.
|
13
|
+
# @param [String] string serialized json.
|
14
|
+
# @return [Array<Hash>] an array of hashes.
|
15
|
+
def parse(string)
|
16
|
+
results = []
|
17
|
+
parser.parse(string) { |hash| results << hash }
|
18
|
+
results
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @private
|
24
|
+
# Memoized parser instance.
|
25
|
+
def parser
|
26
|
+
@parser ||= ::Yajl::Parser.new(symbolize_keys: true)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -27,7 +27,7 @@ module OandaAPI
|
|
27
27
|
#
|
28
28
|
# # -- Stopping the stream --
|
29
29
|
# # You may add a second argument to the block to yield the client itself.
|
30
|
-
# # You can use
|
30
|
+
# # You can use it to issue a client.stop! to terminate streaming.
|
31
31
|
# @prices = []
|
32
32
|
# prices = client.prices(account_id: 1234, instruments: %w[AUD_CAD AUD_CHF])
|
33
33
|
# prices.stream do |price, client|
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require_relative 'adapter_error'
|
2
|
+
|
3
|
+
module OandaAPI
|
4
|
+
module Streaming
|
5
|
+
#
|
6
|
+
# Used to deserialize a stream of JSON objects. Will load and use a streaming JSON parser
|
7
|
+
# if one is installed, otherwise defaults to use the JSON gem.
|
8
|
+
module JsonParser
|
9
|
+
extend self
|
10
|
+
|
11
|
+
# Map parser adapters to the gem library they require.
|
12
|
+
REQUIREMENT_MAP = {
|
13
|
+
gson: "Gson",
|
14
|
+
yajl: "Yajl"
|
15
|
+
}
|
16
|
+
|
17
|
+
# Loads (if not already loaded) and returns the current adapter class.
|
18
|
+
# @return [.parse] a class implementing a `.parse` method
|
19
|
+
def adapter
|
20
|
+
return @adapter if defined?(@adapter) && @adapter
|
21
|
+
|
22
|
+
# Load default adapter
|
23
|
+
self.use nil
|
24
|
+
@adapter
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a symbol identifying either the currently loaded adapter or
|
28
|
+
# one that can be loaded. Preference is given to an adapter optimized
|
29
|
+
# for parsing streaming json if it is installed.
|
30
|
+
#
|
31
|
+
# @return [Symbol] a symbol identifying an adapter either currently loaded or that
|
32
|
+
# one that can be loaded.
|
33
|
+
def default_adapter
|
34
|
+
jruby? ? try_adapter(:gson) : try_adapter(:yajl)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Loads the requested adapter.
|
38
|
+
# @param [nil, String, Symbol, Module, Class] new_adapter identifies an adapter to load.
|
39
|
+
# @return[.parse] a Module or Class that implements a `.parse` method for deserializing a stream of JSON objects.
|
40
|
+
def use(new_adapter)
|
41
|
+
@adapter = load_adapter(new_adapter)
|
42
|
+
end
|
43
|
+
alias adapter= use
|
44
|
+
|
45
|
+
# Loads the requested adapter.
|
46
|
+
# @param [String, Symbol, nil, false, Class, Module] new_adapter identifies an adapter to load.
|
47
|
+
# @return [.parse] a Module or Class that implements a `.parse` method for deserializing a stream of JSON objects.
|
48
|
+
# @raise [AdapterError] if the adapter cannot be loaded.
|
49
|
+
def load_adapter(new_adapter)
|
50
|
+
case new_adapter
|
51
|
+
when String, Symbol
|
52
|
+
load_adapter_from_string_name new_adapter.to_s
|
53
|
+
when NilClass, FalseClass
|
54
|
+
load_adapter default_adapter
|
55
|
+
when Class, Module
|
56
|
+
new_adapter
|
57
|
+
else
|
58
|
+
fail ::LoadError, new_adapter
|
59
|
+
end
|
60
|
+
rescue ::LoadError => exception
|
61
|
+
raise AdapterError.build(exception)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# @return [true] if jRuby is the ruby execution engine
|
67
|
+
def jruby?
|
68
|
+
defined?(RUBY_ENGINE) && (RUBY_ENGINE =~ /jruby/i)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Loads the requested adapter.
|
72
|
+
# @param [String] name the adapter to load.
|
73
|
+
# @return [Class, Module] the loaded adapter
|
74
|
+
def load_adapter_from_string_name(name)
|
75
|
+
require_relative "adapters/#{name.downcase}"
|
76
|
+
klass_name = name.to_s.split('_').map(&:capitalize) * ''
|
77
|
+
OandaAPI::Streaming::Adapters.const_get(klass_name)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Checks if the requested adapter is loadable.
|
81
|
+
# Returns a symbol identifiying either the requested adapter or
|
82
|
+
# a generic loadable adapter.
|
83
|
+
# @param [Symbol] sym identifies an adapter.
|
84
|
+
# @return [Symbol] a symbol identifying a loadable adapter.
|
85
|
+
def try_adapter(sym)
|
86
|
+
begin
|
87
|
+
return sym if Kernel.const_get sym.to_s.capitalize
|
88
|
+
rescue ::NameError
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
require REQUIREMENT_MAP.fetch sym
|
93
|
+
return sym
|
94
|
+
rescue ::LoadError
|
95
|
+
warning
|
96
|
+
return :generic
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Writes a warning to stdout about the generic json parser.
|
101
|
+
# @return[void]
|
102
|
+
def warning
|
103
|
+
Kernel.warn <<-END
|
104
|
+
+------------------------------------------------------------------+
|
105
|
+
+ Warning: You're currently using a JSON parser that doesn't +
|
106
|
+
+ handle streams of JSON objects very well. For faster +
|
107
|
+
+ and more reliable parsing, it's recommended to install one of +
|
108
|
+
+ following gems dependent on the Ruby engine you're using. Once +
|
109
|
+
+ installed, OandaAPI::Streaming will detect the upgraded parser +
|
110
|
+
+ and use it. +
|
111
|
+
+ +
|
112
|
+
+ RUBY_ENGINE Recommended JSON Parsing Gem +
|
113
|
+
+ =========== ================================================== +
|
114
|
+
+ ruby or rbx yajl-ruby (http://github.com/brianmario/yajl-ruby) +
|
115
|
+
+ install with: gem install yajl-ruby +
|
116
|
+
+ +
|
117
|
+
+ +
|
118
|
+
+ jruby gson (https://github.com/avsej/gson.rb) +
|
119
|
+
+ install with: gem install gson +
|
120
|
+
+------------------------------------------------------------------+
|
121
|
+
END
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -9,7 +9,7 @@ module OandaAPI
|
|
9
9
|
# @return [OandaAPI::Streaming::Client] a streaming client instance.
|
10
10
|
#
|
11
11
|
# @!attribute [rw] emit_heartbeats
|
12
|
-
# @return [boolean]
|
12
|
+
# @return [boolean] true if heartbeats are emitted.
|
13
13
|
#
|
14
14
|
# @!attribute [r] uri
|
15
15
|
# @return [URI::HTTPS] a URI instance.
|
@@ -20,14 +20,14 @@ module OandaAPI
|
|
20
20
|
attr_accessor :client, :emit_heartbeats
|
21
21
|
attr_reader :uri, :request
|
22
22
|
|
23
|
-
# Creates
|
24
|
-
# @param [Streaming::Client] client a streaming client instance
|
25
|
-
# send signals to an instance of this Streaming::Request.
|
23
|
+
# Creates a `Streaming::Request` instance.
|
24
|
+
# @param [Streaming::Client] client a streaming client instance which can be used to
|
25
|
+
# send signals to an instance of this `Streaming::Request` class.
|
26
26
|
# @param [String] uri an absolute URI to the service endpoint.
|
27
27
|
# @param [Hash] query a list of query parameters, unencoded. The list
|
28
|
-
# is converted into a query string. See
|
28
|
+
# is converted into a query string. See `OandaAPI::Client#query_string_normalizer`.
|
29
29
|
# @param [Hash] headers a list of header values that will be sent with the request.
|
30
|
-
def initialize(client: nil, uri
|
30
|
+
def initialize(client: nil, uri: nil, query: {}, headers: {})
|
31
31
|
self.client = client.nil? ? self : client
|
32
32
|
@uri = URI uri
|
33
33
|
@uri.query = OandaAPI::Client.default_options[:query_string_normalizer].call(query)
|
@@ -41,9 +41,9 @@ module OandaAPI
|
|
41
41
|
# Sets the client attribute
|
42
42
|
# @param [OandaAPI::Streaming::Client] value
|
43
43
|
# @return [void]
|
44
|
-
# @raise [ArgumentError] if value is not an OandaAPI::Streaming::Client instance.
|
44
|
+
# @raise [ArgumentError] if value is not an {OandaAPI::Streaming::Client} instance.
|
45
45
|
def client=(value)
|
46
|
-
fail ArgumentError, "Expecting an OandaAPI::Streaming::Client" unless
|
46
|
+
fail ArgumentError, "Expecting an OandaAPI::Streaming::Client" unless value.is_a?(OandaAPI::Streaming::Client) || value.is_a?(OandaAPI::Streaming::Request)
|
47
47
|
@client = value
|
48
48
|
end
|
49
49
|
|
@@ -64,7 +64,7 @@ module OandaAPI
|
|
64
64
|
!!@stop_requested
|
65
65
|
end
|
66
66
|
|
67
|
-
# @return [
|
67
|
+
# @return [boolean] true if the instance is connected and is streaming a response.
|
68
68
|
def running?
|
69
69
|
!!@running
|
70
70
|
end
|
@@ -72,15 +72,15 @@ module OandaAPI
|
|
72
72
|
# Emits a stream of {OandaAPI::ResourceBase} instances, depending
|
73
73
|
# on the endpoint that the request is servicing, either
|
74
74
|
# {OandaAPI::Resource::Price} or {OandaAPI::Resource::Transaction}
|
75
|
-
# instances are emitted. When #emit_heartbeats? is `true`, then
|
76
|
-
#
|
75
|
+
# instances are emitted. When {#emit_heartbeats?} is `true`, then
|
76
|
+
# {OandaAPI::Resource::Heartbeat} could also be emitted.
|
77
77
|
#
|
78
78
|
# Note this method runs as an infinite loop and will block indefinitely
|
79
79
|
# until either the connection is halted or a {#stop!} signal is recieved.
|
80
80
|
#
|
81
81
|
# @yield [OandaAPI::ResourceBase, OandaAPI::Streaming::Client] Each resource found in the response
|
82
82
|
# stream is yielded as they are received. The client instance controlling the
|
83
|
-
# streaming request is also yielded. It can be used to issue a
|
83
|
+
# streaming request is also yielded. It can be used to issue a `client.stop!` to terminate the resquest.
|
84
84
|
# @raise [OandaAPI::StreamingDisconnect] if the endpoint was disconnected by server.
|
85
85
|
# @raise [OandaAPI::RequestError] if an unexpected resource is returned.
|
86
86
|
# @return [void]
|
@@ -113,23 +113,28 @@ module OandaAPI
|
|
113
113
|
# When #emit_heartbeats? is `true`, then the instance could be an {OandaAPI::Resource::Heartbeat}.
|
114
114
|
# @raise [OandaAPI::StreamingDisconnect] if the endpoint was disconnected by server.
|
115
115
|
# @raise [OandaAPI::RequestError] if an unexpected resource is returned.
|
116
|
-
def handle_response(
|
117
|
-
|
118
|
-
parsed_response = JSON.parse json
|
116
|
+
def handle_response(string)
|
117
|
+
parse(string).map do |parsed_response|
|
119
118
|
case
|
120
|
-
when parsed_response[
|
121
|
-
OandaAPI::Resource::Heartbeat.new parsed_response[
|
122
|
-
when parsed_response[
|
123
|
-
OandaAPI::Resource::Price.new parsed_response[
|
124
|
-
when parsed_response[
|
125
|
-
OandaAPI::Resource::Transaction.new parsed_response[
|
126
|
-
when parsed_response[
|
127
|
-
|
119
|
+
when parsed_response[:heartbeat]
|
120
|
+
OandaAPI::Resource::Heartbeat.new parsed_response[:heartbeat] if emit_heartbeats?
|
121
|
+
when parsed_response[:tick]
|
122
|
+
OandaAPI::Resource::Price.new parsed_response[:tick]
|
123
|
+
when parsed_response[:transaction]
|
124
|
+
OandaAPI::Resource::Transaction.new parsed_response[:transaction]
|
125
|
+
when parsed_response[:disconnect]
|
126
|
+
fail OandaAPI::StreamingDisconnect, parsed_response[:disconnect][:message]
|
128
127
|
else
|
129
|
-
|
128
|
+
fail OandaAPI::RequestError, "unknown resource: #{parsed_response}"
|
130
129
|
end
|
131
130
|
end.compact
|
132
131
|
end
|
132
|
+
|
133
|
+
# @private
|
134
|
+
# Uses the best json parser available for optimal performance and stream parsing ability.
|
135
|
+
def parse(string)
|
136
|
+
OandaAPI::Streaming::JsonParser.adapter.parse string
|
137
|
+
end
|
133
138
|
end
|
134
139
|
end
|
135
140
|
end
|
data/lib/oanda_api/version.rb
CHANGED
data/oanda_api.gemspec
CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
22
|
s.require_paths = ["lib"]
|
23
23
|
|
24
|
-
s.add_dependency "httparty", "
|
24
|
+
s.add_dependency "httparty", "0.13.3"
|
25
25
|
s.add_dependency "persistent_httparty", "~> 0.1"
|
26
26
|
s.add_dependency "http-exceptions", "~> 0.0"
|
27
27
|
|
28
|
-
s.add_development_dependency "rspec", "~> 3.
|
28
|
+
s.add_development_dependency "rspec", "~> 3.2"
|
29
29
|
s.add_development_dependency "vcr", "~> 2.9"
|
30
|
-
s.add_development_dependency "webmock", "~> 1.
|
30
|
+
s.add_development_dependency "webmock", "~> 1.21"
|
31
31
|
s.add_development_dependency "yard", "~> 0.8"
|
32
32
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "OandaAPI::Client::JsonParser" do
|
4
|
+
|
5
|
+
it "deserializes json using symbolized keys" do
|
6
|
+
[
|
7
|
+
["{\"a\":[{\"b\":{\"3\":3}}]}", { :a => [:b => { :"3" => 3 }] }],
|
8
|
+
[ "\r\n \r\n {\"a\":\"a\"} \r\n ", { :a => "a"}]
|
9
|
+
].each do |serialized, deserialized|
|
10
|
+
expect(OandaAPI::Client::JsonParser.call serialized, :json).to eq(deserialized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -43,5 +43,11 @@ describe "OandaAPI::ResourceBase" do
|
|
43
43
|
h = JSON.parse obj.to_json
|
44
44
|
expect(h).to include("webbed_feet" => "customized webbed feet")
|
45
45
|
end
|
46
|
+
|
47
|
+
it "serializes when nested" do
|
48
|
+
obj = MyCustomizedClass.new webbedFeet: "webbed feet"
|
49
|
+
a = JSON.parse [obj].to_json
|
50
|
+
expect(a.first).to include("webbed_feet" => "customized webbed feet")
|
51
|
+
end
|
46
52
|
end
|
47
53
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "OandaAPI::Streaming::JsonParser" do
|
4
|
+
|
5
|
+
context "when no streaming json parsers are available" do
|
6
|
+
around do |example|
|
7
|
+
simulate_no_adapters{ example.call }
|
8
|
+
end
|
9
|
+
|
10
|
+
it "defaults to :generic adapter" do
|
11
|
+
silence_warnings do
|
12
|
+
expect(OandaAPI::Streaming::JsonParser.default_adapter).to eq(:generic)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "prints a warning about using a non-optimal JSON parser" do
|
17
|
+
expect(Kernel).to receive(:warn).with(/warning/i)
|
18
|
+
OandaAPI::Streaming::JsonParser.default_adapter
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "defaults to the best available JSON parser for jruby", :if => gem_installed?(:Gson) do
|
23
|
+
# Clear memoized variable that may have been set by previous tests
|
24
|
+
OandaAPI::Streaming::JsonParser.send(:remove_instance_variable, :@adapter) if OandaAPI::Streaming::JsonParser.instance_variable_defined?(:@adapter)
|
25
|
+
expect(OandaAPI::Streaming::JsonParser.adapter.to_s).to eq("OandaAPI::Streaming::Adapters::Gson")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "defaults to the best available JSON parser for non-jruby", :if => gem_installed?(:Yajl) do
|
29
|
+
# Clear memoized variable that may have been set by previous tests
|
30
|
+
OandaAPI::Streaming::JsonParser.send(:remove_instance_variable, :@adapter) if OandaAPI::Streaming::JsonParser.instance_variable_defined?(:@adapter)
|
31
|
+
expect(OandaAPI::Streaming::JsonParser.adapter.to_s).to eq("OandaAPI::Streaming::Adapters::Yajl")
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "explicitly overriding the adapter" do
|
35
|
+
after(:each) do
|
36
|
+
OandaAPI::Streaming::JsonParser.adapter = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'is settable via a symbol' do
|
40
|
+
OandaAPI::Streaming::JsonParser.use :generic
|
41
|
+
expect(OandaAPI::Streaming::JsonParser.adapter).to eq(OandaAPI::Streaming::Adapters::Generic)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'is settable via a case-insensitive string' do
|
45
|
+
OandaAPI::Streaming::JsonParser.use 'generic'
|
46
|
+
expect(OandaAPI::Streaming::JsonParser.adapter).to eq(OandaAPI::Streaming::Adapters::Generic)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'is settable via a class' do
|
50
|
+
adapter = Class.new
|
51
|
+
OandaAPI::Streaming::JsonParser.use adapter
|
52
|
+
expect(OandaAPI::Streaming::JsonParser.adapter).to eq(adapter)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'is settable via a module' do
|
56
|
+
adapter = Module.new
|
57
|
+
OandaAPI::Streaming::JsonParser.use adapter
|
58
|
+
expect(OandaAPI::Streaming::JsonParser.adapter).to eq(adapter)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'throws AdapterError on bad input' do
|
63
|
+
expect{ OandaAPI::Streaming::JsonParser.use 'bad adapter' }.to raise_error(OandaAPI::Streaming::AdapterError, /bad adapter/)
|
64
|
+
end
|
65
|
+
end
|
@@ -3,6 +3,7 @@ require 'uri'
|
|
3
3
|
require 'webmock/rspec'
|
4
4
|
|
5
5
|
describe "OandaAPI::Streaming::Request" do
|
6
|
+
|
6
7
|
let(:streaming_request) {
|
7
8
|
OandaAPI::Streaming::Request.new(uri: "https://a.url.com",
|
8
9
|
query: { account: 1234, instruments: %w[AUD_CAD AUD_CHF] },
|
@@ -60,7 +61,10 @@ describe "OandaAPI::Streaming::Request" do
|
|
60
61
|
END
|
61
62
|
ids = []
|
62
63
|
stub_request(:any, /\.com/).to_return(body: events_json, status: 200)
|
63
|
-
|
64
|
+
|
65
|
+
streaming_request.stream do |resource|
|
66
|
+
ids << resource.id
|
67
|
+
end
|
64
68
|
expect(ids).to contain_exactly(1, 2)
|
65
69
|
end
|
66
70
|
|
@@ -168,5 +172,29 @@ describe "OandaAPI::Streaming::Request" do
|
|
168
172
|
expect(heartbeats).to eq 1
|
169
173
|
end
|
170
174
|
end
|
175
|
+
|
176
|
+
context "when the stream contains multiple undelimited objects" do
|
177
|
+
events_json = <<-END
|
178
|
+
{"tick":{"bid": 1}}{"tick":{"bid": 2}}\r\n{"tick":{"bid": 3}}
|
179
|
+
END
|
180
|
+
|
181
|
+
it "yields all of the objects" do
|
182
|
+
case
|
183
|
+
when gem_installed?(:Yajl)
|
184
|
+
OandaAPI::Streaming::JsonParser.use(:yajl)
|
185
|
+
when gem_installed?(:Gson)
|
186
|
+
OandaAPI::Streaming::JsonParser.use(:gson)
|
187
|
+
else
|
188
|
+
OandaAPI::Streaming::JsonParser.use(:generic)
|
189
|
+
end
|
190
|
+
|
191
|
+
stub_request(:any, /\.com/).to_return(body: events_json, status: 200)
|
192
|
+
ticks = []
|
193
|
+
streaming_request.stream do |resource|
|
194
|
+
ticks << resource.bid
|
195
|
+
end
|
196
|
+
expect(ticks).to contain_exactly(1, 2, 3)
|
197
|
+
end
|
198
|
+
end
|
171
199
|
end
|
172
200
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for 'an adapter' do |adapter|
|
2
|
+
|
3
|
+
before{ OandaAPI::Streaming::JsonParser.use adapter }
|
4
|
+
|
5
|
+
describe ".parse" do
|
6
|
+
it "deserializes json using symbolized keys" do
|
7
|
+
[
|
8
|
+
["{\"a\":[{\"b\":{\"3\":3}}]}", [{ :a => [:b => { :"3" => 3 }] }]],
|
9
|
+
["{\"a\":\"a\"} \r\n ", [{ :a => "a"}]],
|
10
|
+
["", []],
|
11
|
+
[" ", []],
|
12
|
+
["\r\n", []]
|
13
|
+
|
14
|
+
].each do |serialized, deserialized|
|
15
|
+
expect(OandaAPI::Streaming::JsonParser.adapter.parse(serialized)).to eq(deserialized)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
lib = File.expand_path("../../lib", __FILE__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
|
+
require 'codeclimate-test-reporter'
|
5
|
+
CodeClimate::TestReporter.start
|
6
|
+
|
4
7
|
require 'simplecov'
|
5
8
|
SimpleCov.start
|
6
9
|
|
@@ -12,3 +15,64 @@ RSpec.configure do |c|
|
|
12
15
|
OandaAPI.configure { |config| config.use_request_throttling = false }
|
13
16
|
end
|
14
17
|
end
|
18
|
+
|
19
|
+
def jruby?
|
20
|
+
defined?(RUBY_ENGINE) && (RUBY_ENGINE =~ /jruby/i)
|
21
|
+
end
|
22
|
+
|
23
|
+
def gem_installed?(const)
|
24
|
+
begin
|
25
|
+
require const.to_s.downcase unless Object.const_defined? const
|
26
|
+
true
|
27
|
+
rescue ::LoadError => e
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Makes the adapter requirements break (i.e. simulates that a gem required
|
33
|
+
# for an adapter is not installed).
|
34
|
+
def break_requirements
|
35
|
+
requirements = OandaAPI::Streaming::JsonParser::REQUIREMENT_MAP
|
36
|
+
OandaAPI::Streaming::JsonParser::REQUIREMENT_MAP.each do | adapter, library|
|
37
|
+
OandaAPI::Streaming::JsonParser::REQUIREMENT_MAP[adapter] = "foo/#{library}"
|
38
|
+
end
|
39
|
+
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
requirements.keys do |adapter|
|
43
|
+
OandaAPI::Streaming::JsonParser::REQUIREMENT_MAP[adapter] = requirements[adapter]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Silences warnings issued by Kerel.warn
|
48
|
+
def silence_warnings
|
49
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
50
|
+
yield
|
51
|
+
ensure
|
52
|
+
$VERBOSE = old_verbose
|
53
|
+
end
|
54
|
+
|
55
|
+
def simulate_no_adapters
|
56
|
+
break_requirements do
|
57
|
+
undefine_constants :Yajl, :Gson do
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def undefine_constants(*consts)
|
64
|
+
values = {}
|
65
|
+
consts.each do |const|
|
66
|
+
if Object.const_defined?(const)
|
67
|
+
values[const] = Object.const_get(const)
|
68
|
+
Object.send :remove_const, const
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
yield
|
73
|
+
|
74
|
+
ensure
|
75
|
+
values.each do |const, value|
|
76
|
+
Object.const_set const, value
|
77
|
+
end
|
78
|
+
end
|
data/spec/support/vcr.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oanda_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dean Missikowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.13.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.13.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: persistent_httparty
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
61
|
+
version: '3.2'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
68
|
+
version: '3.2'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: vcr
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '1.
|
89
|
+
version: '1.21'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '1.
|
96
|
+
version: '1.21'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: yard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,6 +127,7 @@ files:
|
|
127
127
|
- Rakefile
|
128
128
|
- lib/oanda_api.rb
|
129
129
|
- lib/oanda_api/client/client.rb
|
130
|
+
- lib/oanda_api/client/json_parser.rb
|
130
131
|
- lib/oanda_api/client/namespace_proxy.rb
|
131
132
|
- lib/oanda_api/client/resource_descriptor.rb
|
132
133
|
- lib/oanda_api/client/token_client.rb
|
@@ -144,7 +145,12 @@ files:
|
|
144
145
|
- lib/oanda_api/resource/transaction.rb
|
145
146
|
- lib/oanda_api/resource_base.rb
|
146
147
|
- lib/oanda_api/resource_collection.rb
|
148
|
+
- lib/oanda_api/streaming/adapter_error.rb
|
149
|
+
- lib/oanda_api/streaming/adapters/generic.rb
|
150
|
+
- lib/oanda_api/streaming/adapters/gson.rb
|
151
|
+
- lib/oanda_api/streaming/adapters/yajl.rb
|
147
152
|
- lib/oanda_api/streaming/client.rb
|
153
|
+
- lib/oanda_api/streaming/json_parser.rb
|
148
154
|
- lib/oanda_api/streaming/request.rb
|
149
155
|
- lib/oanda_api/utils/utils.rb
|
150
156
|
- lib/oanda_api/version.rb
|
@@ -176,6 +182,7 @@ files:
|
|
176
182
|
- spec/fixtures/vcr_cassettes/sandbox_client_account.yml
|
177
183
|
- spec/fixtures/vcr_cassettes/sandbox_instrument_EUR_USD.yml
|
178
184
|
- spec/oanda_api/client/client_spec.rb
|
185
|
+
- spec/oanda_api/client/json_parser_spec.rb
|
179
186
|
- spec/oanda_api/client/namespace_proxy_spec.rb
|
180
187
|
- spec/oanda_api/client/resource_descriptor_spec.rb
|
181
188
|
- spec/oanda_api/client/token_client_spec.rb
|
@@ -189,9 +196,14 @@ files:
|
|
189
196
|
- spec/oanda_api/examples/transactions_spec.rb
|
190
197
|
- spec/oanda_api/resource_base_spec.rb
|
191
198
|
- spec/oanda_api/resource_collection_spec.rb
|
199
|
+
- spec/oanda_api/streaming/adapters/generic_spec.rb
|
200
|
+
- spec/oanda_api/streaming/adapters/gson_spec.rb
|
201
|
+
- spec/oanda_api/streaming/adapters/yajl_spec.rb
|
192
202
|
- spec/oanda_api/streaming/client_spec.rb
|
203
|
+
- spec/oanda_api/streaming/json_parser_spec.rb
|
193
204
|
- spec/oanda_api/streaming/request_spec.rb
|
194
205
|
- spec/oanda_api/utils/utils_spec.rb
|
206
|
+
- spec/shared/adapter.rb
|
195
207
|
- spec/spec_helper.rb
|
196
208
|
- spec/support/client_helper.rb
|
197
209
|
- spec/support/vcr.rb
|
@@ -247,6 +259,7 @@ test_files:
|
|
247
259
|
- spec/fixtures/vcr_cassettes/sandbox_client_account.yml
|
248
260
|
- spec/fixtures/vcr_cassettes/sandbox_instrument_EUR_USD.yml
|
249
261
|
- spec/oanda_api/client/client_spec.rb
|
262
|
+
- spec/oanda_api/client/json_parser_spec.rb
|
250
263
|
- spec/oanda_api/client/namespace_proxy_spec.rb
|
251
264
|
- spec/oanda_api/client/resource_descriptor_spec.rb
|
252
265
|
- spec/oanda_api/client/token_client_spec.rb
|
@@ -260,9 +273,14 @@ test_files:
|
|
260
273
|
- spec/oanda_api/examples/transactions_spec.rb
|
261
274
|
- spec/oanda_api/resource_base_spec.rb
|
262
275
|
- spec/oanda_api/resource_collection_spec.rb
|
276
|
+
- spec/oanda_api/streaming/adapters/generic_spec.rb
|
277
|
+
- spec/oanda_api/streaming/adapters/gson_spec.rb
|
278
|
+
- spec/oanda_api/streaming/adapters/yajl_spec.rb
|
263
279
|
- spec/oanda_api/streaming/client_spec.rb
|
280
|
+
- spec/oanda_api/streaming/json_parser_spec.rb
|
264
281
|
- spec/oanda_api/streaming/request_spec.rb
|
265
282
|
- spec/oanda_api/utils/utils_spec.rb
|
283
|
+
- spec/shared/adapter.rb
|
266
284
|
- spec/spec_helper.rb
|
267
285
|
- spec/support/client_helper.rb
|
268
286
|
- spec/support/vcr.rb
|