Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 7 commits
  • 20 files changed
  • 0 commit comments
  • 1 contributor
View
4 HISTORY
@@ -173,3 +173,7 @@
== 0.7.9 / 2012-04-24
* Order and OrderState API extended
+
+== 0.7.10 / 2012-04-25
+
+* Small fixes for DB backend and serialization
View
27 README.md
@@ -71,7 +71,6 @@ other API implementations. The choice is yours.
| 0.6.1 | 921-923 | 966 |
| 0.7.1+ | 924+ | 967 |
-
4. Start Interactive Broker's Trader Work Station or Gateway before your code
attempts to connect to it. Note that TWS and Gateway listen to different ports,
this library assumes connection to Gateway on the same machine (localhost:4001)
@@ -143,6 +142,32 @@ You can easily create your own tests following the guide in 'spec/README'.
Help the development! See 'spec/TODO' for the list of use cases/scenarios
that still need to be tested.
+## DB BACKEND:
+
+Latest versions of the gem added (optional and experimental) support for data
+persistance (ActiveRecord ORM). In order to use this support, you have to set up
+the database (SQLite recommended for simplicity) and run migrations located at
+'db/migrate' folder.
+
+You further need to:
+
+ require 'ib-ruby/db'
+
+ IB::DB.connect :adapter => 'sqlite3',
+ :database => 'db/test.sqlite3'
+
+ require 'ib-ruby'
+
+Only require 'ib-ruby' AFTER you connected to DB, otherwise your Models will not
+inherit from ActiveRecord::Base and won't be persistent. If you are using Rails,
+you don't need IB::DB.connect part, Rails will take care of it for you. So, just use:
+
+ require 'ib-ruby/db'
+ require 'ib-ruby'
+
+Now, all your IB Models are just ActiveRecords and you can do whatever you want with them:
+persist to DB, use in Rails applications, develop controllers and views.
+
## LICENSE:
This software is available under the LGPL.
View
2  VERSION
@@ -1 +1 @@
-0.7.9
+0.7.10
View
5 ib-ruby.gemspec
@@ -13,7 +13,8 @@ Gem::Specification.new do |gem|
# Files setup
versioned = `git ls-files -z`.split("\0")
- gem.files = Dir['{bin,lib,man,spec,features,tasks}/**/*', 'Rakefile', 'README*', 'LICENSE*',
+ gem.files = Dir['{bin,lib,man,spec,features,tasks}/**/*', 'db/migrate/**/*',
+ 'Rakefile', 'README*', 'LICENSE*',
'VERSION*', 'HISTORY*', 'TODO*', '.gitignore'] & versioned
gem.executables = (Dir['bin/**/*'] & versioned).map { |file| File.basename(file) }
gem.test_files = Dir['spec/**/*'] & versioned
@@ -25,9 +26,9 @@ Gem::Specification.new do |gem|
gem.add_dependency 'activerecord-jdbcsqlite3-adapter', '>= 1.2.2'
gem.add_dependency 'jdbc-sqlite3', '>= 3.7.2'
gem.add_dependency 'xml-simple', '>= 1.1.1'
+ gem.add_dependency 'standalone_migrations'
#gem.add_dependency 'pg', '>= 0.12.1'
- gem.add_development_dependency 'standalone_migrations'
gem.add_development_dependency 'database_cleaner', '>= 2.8.0'
gem.add_development_dependency 'rspec', '>= 2.9.0'
gem.add_development_dependency 'my_scripts'
View
4 lib/ib-ruby/models/bag.rb
@@ -22,8 +22,8 @@ def legs_cannot_be_empty
end
def default_attributes
- {:legs => Array.new,
- :sec_type => :bag}.merge super
+ super.merge :legs => Array.new,
+ :sec_type => :bag
end
def description
View
12 lib/ib-ruby/models/combo_leg.rb
@@ -39,12 +39,12 @@ class ComboLeg < Model.for(:combo_leg)
:message => "should be blank or orders will be rejected"
def default_attributes
- {:con_id => 0,
- :open_close => :same, # The only option for retail customers.
- :short_sale_slot => :default,
- :designated_location => '',
- :exchange => 'SMART', # Unless SMART, Order modification fails
- :exempt_code => -1, }.merge super
+ super.merge :con_id => 0,
+ :open_close => :same, # The only option for retail customers.
+ :short_sale_slot => :default,
+ :designated_location => '',
+ :exchange => 'SMART', # Unless SMART, Order modification fails
+ :exempt_code => -1
end
# Leg's weight is a combination of action and ratio
View
10 lib/ib-ruby/models/contract.rb
@@ -95,11 +95,11 @@ class Contract < Model.for(:contract)
validates_numericality_of :multiplier, :strike, :allow_nil => true
def default_attributes
- {:con_id => 0,
- :strike => 0.0,
- :right => :none, # Not an option
- :exchange => 'SMART',
- :include_expired => false, }.merge super
+ super.merge :con_id => 0,
+ :strike => 0.0,
+ :right => :none, # Not an option
+ :exchange => 'SMART',
+ :include_expired => false
end
# This returns an Array of data from the given contract.
View
14 lib/ib-ruby/models/contract_detail.rb
@@ -56,13 +56,13 @@ class ContractDetail < Model.for(:contract_detail)
validates_format_of :time_zone, :with => /^\w{3}$/, :message => 'should be XXX'
def default_attributes
- {:coupon => 0.0,
- :under_con_id => 0,
- :min_tick => 0,
- :callable => false,
- :puttable => false,
- :convertible => false,
- :next_option_partial => false, }.merge super
+ super.merge :coupon => 0.0,
+ :under_con_id => 0,
+ :min_tick => 0,
+ :callable => false,
+ :puttable => false,
+ :convertible => false,
+ :next_option_partial => false
end
end # class ContractDetail
View
14 lib/ib-ruby/models/execution.rb
@@ -7,7 +7,7 @@ class Execution < Model.for(:execution)
belongs_to :order
- prop [:local_id, :order_id], # int: order id. TWS orders have a fixed order id of 0.
+ prop :local_id, # int: order id. TWS orders have a fixed order id of 0.
:client_id, # int: client id. TWS orders have a fixed client id of 0.
:perm_id, # int: TWS id used to identify orders over TWS sessions
:exec_id, # String: Unique order execution id over TWS sessions.
@@ -30,12 +30,12 @@ class Execution < Model.for(:execution)
validates_numericality_of :local_id, :client_id, :perm_id, :only_integer => true
def default_attributes
- {:local_id => 0,
- :client_id => 0,
- :quantity => 0,
- :price => 0,
- :perm_id => 0,
- :liquidation => false, }.merge super
+ super.merge :local_id => 0,
+ :client_id => 0,
+ :quantity => 0,
+ :price => 0,
+ :perm_id => 0,
+ :liquidation => false
end
# Comparison
View
9 lib/ib-ruby/models/model.rb
@@ -21,7 +21,7 @@ def self.for subclass
end
end
- attr_accessor :created_at, :updated_at, :attributes
+ #attr_accessor :attributes
# If a opts hash is given, keys are taken as attribute names, values as data.
# The model instance fields are then set automatically from the opts Hash.
@@ -29,8 +29,7 @@ def initialize opts={}
run_callbacks :initialize do
error "Argument must be a Hash", :args unless opts.is_a?(Hash)
- attrs = default_attributes.merge(opts)
- attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
+ self.attributes = default_attributes.merge(opts)
end
end
@@ -40,6 +39,10 @@ def attributes
@attributes ||= HashWithIndifferentAccess.new
end
+ def attributes= attrs
+ attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
+ end
+
# ActiveModel-style read/write_attribute accessors
def [] key
attributes[key.to_sym]
View
113 lib/ib-ruby/models/model_properties.rb
@@ -49,13 +49,6 @@ def == other
included do
- # Extending AR-backed Model class with attribute defaults
- if defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
- def initialize opts={}
- super default_attributes.merge(opts)
- end
- end
-
### Class macros
def self.prop *properties
@@ -82,59 +75,69 @@ def self.define_property names, body
def self.define_property_methods name, body={}
#p name, body
case body
- when '' # default getter and setter
- define_property_methods name
-
- when Array # [setter, getter, validators]
- define_property_methods name,
- :get => body[0],
- :set => body[1],
- :validate => body[2]
-
- when Hash # recursion base case
- getter = case # Define getter
- when body[:get].respond_to?(:call)
- body[:get]
- when body[:get]
- proc { self[name].send "to_#{body[:get]}" }
- when VALUES[name] # property is encoded
- proc { VALUES[name][self[name]] }
- #when respond_to?(:column_names) && column_names.include?(name.to_s)
- # # noop, ActiveRecord will take care of it...
- # p "#{name} => get noop"
- # p respond_to?(:column_names) && column_names
- else
- proc { self[name] }
- end
- define_method name, &getter if getter
-
- setter = case # Define setter
- when body[:set].respond_to?(:call)
- body[:set]
- when body[:set]
- proc { |value| self[name] = value.send "to_#{body[:set]}" }
- when CODES[name] # property is encoded
- proc { |value| self[name] = CODES[name][value] || value }
- else
- proc { |value| self[name] = value } # p name, value;
- end
- define_method "#{name}=", &setter if setter
-
- # Define validator(s)
- [body[:validate]].flatten.compact.each do |validator|
- case validator
- when Proc
- validates_each name, &validator
- when Hash
- validates name, validator.dup
+ when '' # default getter and setter
+ define_property_methods name
+
+ when Array # [setter, getter, validators]
+ define_property_methods name,
+ :get => body[0],
+ :set => body[1],
+ :validate => body[2]
+
+ when Hash # recursion base case
+ getter = case # Define getter
+ when body[:get].respond_to?(:call)
+ body[:get]
+ when body[:get]
+ proc { self[name].send "to_#{body[:get]}" }
+ when VALUES[name] # property is encoded
+ proc { VALUES[name][self[name]] }
+ #when respond_to?(:column_names) && column_names.include?(name.to_s)
+ # # noop, ActiveRecord will take care of it...
+ # p "#{name} => get noop"
+ # p respond_to?(:column_names) && column_names
+ else
+ proc { self[name] }
+ end
+ define_method name, &getter if getter
+
+ setter = case # Define setter
+ when body[:set].respond_to?(:call)
+ body[:set]
+ when body[:set]
+ proc { |value| self[name] = value.send "to_#{body[:set]}" }
+ when CODES[name] # property is encoded
+ proc { |value| self[name] = CODES[name][value] || value }
+ else
+ proc { |value| self[name] = value } # p name, value;
+ end
+ define_method "#{name}=", &setter if setter
+
+ # Define validator(s)
+ [body[:validate]].flatten.compact.each do |validator|
+ case validator
+ when Proc
+ validates_each name, &validator
+ when Hash
+ validates name, validator.dup
+ end
end
- end
# TODO define self[:name] accessors for :virtual and :flag properties
- else # setter given
- define_property_methods name, :set => body, :get => body
+ else # setter given
+ define_property_methods name, :set => body, :get => body
+ end
+ end
+
+ # Extending AR-backed Model class with attribute defaults
+ if defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
+ def initialize opts={}
+ super default_attributes.merge(opts)
end
+ else
+ # Timestamps
+ prop :created_at, :updated_at
end
end # included
View
2  lib/ib-ruby/models/option.rb
@@ -49,7 +49,7 @@ def self.from_osi osi
end
def default_attributes
- {:sec_type => :option}.merge super
+ super.merge :sec_type => :option
#self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
end
View
69 lib/ib-ruby/models/order.rb
@@ -12,7 +12,7 @@ class Order < Model.for(:order)
# your own Order IDs to avoid conflicts between orders placed from your API application.
# Main order fields
- prop [:local_id, :order_id], # int: Order id associated with client (volatile).
+ prop :local_id, # int: Order id associated with client (volatile).
:client_id, # int: The id of the client that placed this order.
:perm_id, # int: TWS permanent id, remains the same over TWS sessions.
[:quantity, :total_quantity], # int: The order quantity.
@@ -238,10 +238,10 @@ def order_state
def order_state= state
self.order_states.push case state
- when IB::OrderState
- state
- when Symbol, String
- IB::OrderState.new :status => state
+ when IB::OrderState
+ state
+ when Symbol, String
+ IB::OrderState.new :status => state
end
end
@@ -267,13 +267,14 @@ def order_state= state
:why_held, # String: comma-separated list of reasons for order to be held.
# Testing Order state:
:new?,
+ :submitted?,
:pending?,
:active?,
:inactive?,
:complete_fill?,
].each { |property| define_method(property) { order_state.send(property) } }
- # Order is not valid without correct :local_id (:order_id)
+ # Order is not valid without correct :local_id
validates_numericality_of :local_id, :perm_id, :client_id, :parent_id,
:quantity, :min_quantity, :display_size,
:only_integer => true, :allow_nil => true
@@ -282,28 +283,26 @@ def order_state= state
def default_attributes
- {:aux_price => 0.0,
- :discretionary_amount => 0.0,
- :parent_id => 0,
- :tif => :day,
- :order_type => :limit,
- :open_close => :open,
- :origin => :customer,
- :short_sale_slot => :default,
- :trigger_method => :default,
- :oca_type => :none,
- :auction_strategy => :none,
- :designated_location => '',
- :exempt_code => -1,
- :display_size => 0,
- :continuous_update => 0,
- :delta_neutral_con_id => 0,
- :algo_strategy => '',
- :transmit => true,
- :what_if => false,
- :order_state => IB::OrderState.new(:status => 'New'),
- # TODO: Add simple defaults to prop ?
- }.merge super
+ super.merge :aux_price => 0.0,
+ :discretionary_amount => 0.0,
+ :parent_id => 0,
+ :tif => :day,
+ :order_type => :limit,
+ :open_close => :open,
+ :origin => :customer,
+ :short_sale_slot => :default,
+ :trigger_method => :default,
+ :oca_type => :none,
+ :auction_strategy => :none,
+ :designated_location => '',
+ :exempt_code => -1,
+ :display_size => 0,
+ :continuous_update => 0,
+ :delta_neutral_con_id => 0,
+ :algo_strategy => '',
+ :transmit => true,
+ :what_if => false,
+ :order_state => IB::OrderState.new(:status => 'New')
end
#after_initialize do #opts = {}
@@ -319,12 +318,12 @@ def serialize_with server, contract
[contract.serialize_long(:con_id, :sec_id),
# main order fields
case side
- when :short
- 'SSHORT'
- when :short_exempt
- 'SSHORTX'
- else
- side.to_sup
+ when :short
+ 'SSHORT'
+ when :short_exempt
+ 'SSHORTX'
+ else
+ side.to_sup
end,
quantity,
self[:order_type], # Internal code, 'LMT' instead of :limit
@@ -469,7 +468,7 @@ def place contract, connection
modify contract, connection, self.placed_at
end
- # Modify Order (convenience wrapper for send_message :PlaceOrder). Returns order_id.
+ # Modify Order (convenience wrapper for send_message :PlaceOrder). Returns local_id.
def modify contract, connection, time=Time.now
self.modified_at = time
connection.send_message :PlaceOrder,
View
16 lib/ib-ruby/models/order_state.rb
@@ -27,7 +27,7 @@ class OrderState < Model.for(:order_state)
:why_held # String: comma-separated list of reasons for order to be held.
# Properties arriving in both messages:
- prop [:local_id, :order_id], # int: Order id associated with client (volatile).
+ prop :local_id, # int: Order id associated with client (volatile).
:perm_id, # int: TWS permanent id, remains the same over TWS sessions.
:client_id, # int: The id of the client that placed this order.
:parent_id, # int: The order ID of the parent (original) order, used
@@ -63,6 +63,13 @@ class OrderState < Model.for(:order_state)
validates_numericality_of :local_id, :perm_id, :client_id, :parent_id, :filled,
:remaining, :only_integer => true, :allow_nil => true
+ def default_attributes
+ super.merge :filled => 0,
+ :remaining => 0,
+ :price => 0.0,
+ :average_price => 0.0
+ end
+
## Testing Order state:
def new?
@@ -70,8 +77,13 @@ def new?
end
# Order is in a valid, working state on TWS side
+ def submitted?
+ status == 'PreSubmitted' || status == 'Submitted'
+ end
+
+ # Order is in a valid, working state on TWS side
def pending?
- status == 'PendingSubmit' || status == 'PreSubmitted' || status == 'Submitted'
+ submitted? || status == 'PendingSubmit'
end
# Order is in invalid state
View
2  lib/ib-ruby/models/underlying.rb
@@ -16,7 +16,7 @@ class Underlying < Model.for(:underlying)
validates_numericality_of :con_id, :delta, :price #, :allow_nil => true
def default_attributes
- {:con_id => 0}.merge super
+ super.merge :con_id => 0
end
# Serialize under_comp parameters
View
82 spec/db_helper.rb
@@ -73,29 +73,77 @@
end
shared_examples_for 'Model with associations' do
+
it 'works with associations, if any' do
if defined? associations
- associations.each do |assoc, items|
- proxy = subject.association(assoc).reflection
- #pp proxy
- owner_name = described_class.to_s.demodulize.tableize.singularize
+ subject_name_plural = described_class.to_s.demodulize.tableize
+
+ associations.each do |name, item|
+ puts "Testing single association #{name}"
+ subject.association(name).reflection.should_not be_collection
+
+ # Assign item to association
+ expect { subject.send "#{name}=", item }.to_not raise_error
+
+ association = subject.send name #, :reload
+ association.should == item
+ association.should be_new_record
+
+ # Reverse association does not include subject
+ reverse_association = association.send(subject_name_plural)
+ reverse_association.should be_empty
+
+ # Now let's save subject
+ if subject.valid?
+ subject.save
+
+ association = subject.send name
+ association.should_not be_new_record
+
+ # Reverse association now DOES include subject (if reloaded!)
+ reverse_association = association.send(subject_name_plural, :reload)
+ reverse_association.should include subject
+ end
+ end
+ end
+ end
+
+ it 'works with associated collections, if any' do
+ if defined? collections
+
+ subject_name = described_class.to_s.demodulize.tableize.singularize
+
+ collections.each do |name, items|
+ puts "Testing associated collection #{name}"
+ subject.association(name).reflection.should be_collection
+
[items].flatten.each do |item|
- if proxy.collection?
- association = subject.send("#{assoc}")
- association << item
+ association = subject.send name #, :reload
+
+ # Add item to collection
+ expect { association << item }.to_not raise_error
+ association.should include item
+
+ # Reverse association does NOT point to subject
+ reverse_association = association.first.send(subject_name)
+ #reverse_association.should be_nil # But not always!
+
+ #association.size.should == items.size # Not for Order, +1 OrderState
+ end
+
+ # Now let's save subject
+ if subject.valid?
+ subject.save
+
+ [items].flatten.each do |item|
+ association = subject.send name #, :reload
- p 'collection'
association.should include item
- #p association.first.send(owner_name)
- #.should include item
- #association.
- #association.size.should == items.size # Not for Order, +1 OrderState
- else
- subject.send "#{assoc}=", item
- association = subject.send("#{assoc}")
- p 'not a collection'
- association.should == item
+
+ # Reverse association DOES point to subject now
+ reverse_association = association.first.send(subject_name)
+ reverse_association.should == subject
end
end
View
74 spec/ib-ruby/models/execution_spec.rb
@@ -31,14 +31,14 @@
end
let(:assigns) do
- {[:perm_id, :client_id, :cumulative_quantity, :price, :average_price] => numeric_assigns,
+ {[:local_id, :perm_id, :client_id, :cumulative_quantity, :price, :average_price] =>
+ numeric_assigns,
:liquidation => boolean_assigns,
}
end
let(:aliases) do
{[:side, :action] => buy_sell_assigns,
- [:local_id, :order_id] => numeric_assigns,
[:quantity, :shares] => numeric_assigns,
[:account_name, :account_number]=> string_assigns,
}
@@ -50,54 +50,70 @@
:client_id => 1111,
:parent_id => 0,
:quantity => 100,
+ :side => :buy,
:order_type => :market)
}
end
it_behaves_like 'Model'
- ## TODO: Playing with associations!
- context 'associations' do
+ context 'DB backed associations', :db => true do
subject { IB::Execution.new props }
- before(:all) { DatabaseCleaner.clean if IB::DB }
+ before(:all) { DatabaseCleaner.clean }
it 'saves associated order' do
order = associations[:order]
-
- #p order.save
-
subject.order = order
+ subject.order.should == order
+ subject.order.should be_new_record
- p subject.save
- p subject.errors.messages
+ subject.save
+ subject.order.should_not be_new_record
+ subject.order.executions.should include subject
+ end
+ it 'loads saved association with execution' do
+ order = IB::Order.find(:first)
- p subject.order
- p subject.order.executions
- p subject.to_xml
- p subject.serializable_hash
- p subject.to_json
- p subject.as_json
+ execution = IB::Execution.first
- p IB::Execution.new.from_json subject.to_json # TODO: Strings for keys!
+ execution.should == subject
- pending 'Still need to test associations properly'
+ execution.order.should == order
+ order.executions.first.should == execution
end
+ end
- it 'loads associated execution' do
- pending 'Still need to test associations properly'
-
- #s1 = IB::Execution.first
- #p s1
- #p s1.order.executions
+ context 'extra ActiveModel goodness' do
+ subject { IB::Execution.new props }
- #p o1 = IB::Order.find(:first)
- #p o1.execution
- #
- #p o1.execution.order_id
+ it 'correctly serializes Model into hash and json' do
+ {"account_name"=>"DU111110",
+ "average_price"=>1.31075,
+ "client_id"=>1111,
+ "cumulative_quantity"=>20000,
+ "exchange"=>"IDEALPRO",
+ "exec_id"=>"0001f4e8.4f5d48f1.01.01",
+ "id"=>nil,
+ "liquidation"=>true,
+ "local_id"=>373,
+ "order_ref"=>nil,
+ "perm_id"=>1695693619,
+ "price"=>1.31075,
+ "quantity"=>20000,
+ "time"=>"20120312 15:41:09",
+ "side"=>:buy, }.each do |key, value|
+
+ subject.serializable_hash[key].should == value
+ subject.as_json["execution"][key].should == value
+ end
+
+ subject.to_xml.should =~ /<account-name>DU111110<.account-name>\n <average-price type=\"float\">1.31075<.average-price>\n <client-id type=\"integer\">1111<.client-id>/
+ subject.to_json.should =~ /\{\"execution\":\{\"account_name\":\"DU111110\",\"average_price\":1.31075,\"client_id\":1111,\"/
+
+ IB::Execution.new.from_json(subject.to_json).should == subject
end
-
end
end # describe IB::Models::Contract
View
22 spec/ib-ruby/models/order_spec.rb
@@ -50,17 +50,18 @@
:sweep_to_fill, :override_percentage_constraints, :all_or_none,
:etrade_only, :firm_quote_only, :opt_out_smart_routing, :scale_auto_reset,
:scale_random_percent] => boolean_assigns,
+
+ [:local_id, :perm_id, :parent_id] => numeric_or_nil_assigns,
}
end
let(:aliases) do
{[:side, :action] => buy_sell_short_assigns,
- [:local_id, :order_id] => numeric_or_nil_assigns,
[:quantity, :total_quantity] => numeric_or_nil_assigns,
}
end
- let(:associations) do
+ let(:collections) do
{:order_states => [IB::OrderState.new(:status => :Foo),
IB::OrderState.new(:status => 'Bar'),],
@@ -127,16 +128,17 @@
subject.init_margin.should be_nil
subject.maint_margin.should be_nil
subject.equity_with_loan.should be_nil
- # Properties arriving via OrderStatus messagesubject.
- subject.filled.should be_nil
- subject.remaining.should be_nil
- subject.price.should be_nil
- subject.last_fill_price.should be_nil
- subject.average_price.should be_nil
- subject.average_fill_price.should be_nil
+ # Properties arriving via OrderStatus message
+ subject.filled.should == 0
+ subject.remaining.should == 0
+ subject.price.should == 0
+ subject.last_fill_price.should == 0
+ subject.average_price.should == 0
+ subject.average_fill_price.should == 0
subject.why_held.should be_nil
- # Testing Order statesubject.
+ # Testing Order state
subject.should be_new
+ subject.should_not be_submitted
subject.should_not be_pending
subject.should be_active
subject.should_not be_inactive
View
19 spec/ib-ruby/models/order_state_spec.rb
@@ -38,13 +38,14 @@
let(:assigns) do
{[:status] =>
{[nil, ''] => /must not be empty/,
- ['Zorro', :Zorro] => 'Zorro'}
+ ['Zorro', :Zorro] => 'Zorro'},
+
+ :local_id => numeric_or_nil_assigns,
}
end
let(:aliases) do
- {[:local_id, :order_id] => numeric_or_nil_assigns,
- [:price, :last_fill_price] => float_or_nil_assigns,
+ {[:price, :last_fill_price] => float_or_nil_assigns,
[:average_price, :average_fill_price] => float_or_nil_assigns,
}
end
@@ -53,9 +54,11 @@
it_behaves_like 'Self-equal Model'
context '#update_missing' do
+ let(:nil_state) { IB::OrderState.new(:filled => nil, :remaining => nil,
+ :price => nil, :average_price => nil) }
context 'updating with Hash' do
- subject { IB::OrderState.new.update_missing(props) }
+ subject { nil_state.update_missing(props) }
it_behaves_like 'Model instantiated with properties'
@@ -63,7 +66,7 @@
context 'updating with Model' do
- subject { IB::OrderState.new.update_missing(IB::OrderState.new(props)) }
+ subject { nil_state.update_missing(IB::OrderState.new(props)) }
it_behaves_like 'Model instantiated with properties'
@@ -74,6 +77,8 @@
it 'has extra test methods' do
empty_state = IB::OrderState.new
empty_state.should be_new
+ subject.should_not be_pending
+ subject.should_not be_submitted
empty_state.should be_active
empty_state.should_not be_inactive
empty_state.should_not be_complete_fill
@@ -86,6 +91,7 @@
state.should_not be_inactive
state.should_not be_complete_fill
state.should be_pending
+ status == 'PendingSubmit' ? state.should_not(be_submitted) : state.should(be_submitted)
end
['PendingCancel', 'Cancelled', 'ApiCancelled', 'Inactive'].each do |status|
@@ -95,6 +101,7 @@
state.should be_inactive
state.should_not be_complete_fill
state.should_not be_pending
+ subject.should_not be_submitted
end
state.status = 'Filled'
@@ -103,6 +110,7 @@
state.should be_inactive
state.should_not be_complete_fill
state.should_not be_pending
+ subject.should_not be_submitted
state.remaining = 0
state.should_not be_new
@@ -110,6 +118,7 @@
state.should be_inactive
state.should be_complete_fill
state.should_not be_pending
+ subject.should_not be_submitted
end
end # describe IB::Order
View
13 spec/model_helper.rb
@@ -190,6 +190,7 @@ def test_assigns cases, prop, name
shared_examples_for 'Model instantiated with properties' do
it 'auto-assigns all properties given to initializer' do
props.each do |name, value|
+ #p subject, name, value
subject.send(name).should == value
end
end
@@ -200,6 +201,18 @@ def test_assigns cases, prop, name
shared_examples_for 'Model properties' do
+ it 'leaves order_id alone, no aliasing' do
+ if subject.respond_to?(:order_id)
+ subject.order_id.should be_nil
+ if subject.respond_to?(:local_id=)
+ subject.local_id = 1313
+ subject.order_id.should be_nil
+ subject.order_id = 2222
+ subject.local_id.should == 1313
+ end
+ end
+ end
+
it 'allows setting properties' do
expect {
props.each do |name, value|

No commit comments for this range

Something went wrong with that request. Please try again.