ib-ruby 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY +23 -0
- data/LICENSE +504 -0
- data/README.rdoc +47 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/bin/AccountInfo +67 -0
- data/bin/HistoricToCSV +111 -0
- data/bin/RequestHistoricData +301 -0
- data/bin/RequestMarketData +78 -0
- data/bin/SimpleTimeAndSales +98 -0
- data/bin/ib-ruby +8 -0
- data/lib/ib-ruby/datatypes.rb +400 -0
- data/lib/ib-ruby/ib.rb +242 -0
- data/lib/ib-ruby/messages.rb +1449 -0
- data/lib/ib-ruby/symbols/forex.rb +109 -0
- data/lib/ib-ruby/symbols/futures.rb +109 -0
- data/lib/ib-ruby.rb +10 -0
- data/lib/version.rb +8 -0
- data/spec/ib-ruby_spec.rb +131 -0
- data/spec/spec_helper.rb +11 -0
- data/tasks/common.rake +18 -0
- data/tasks/doc.rake +14 -0
- data/tasks/gem.rake +40 -0
- data/tasks/git.rake +34 -0
- data/tasks/spec.rake +15 -0
- data/tasks/version.rake +71 -0
- metadata +115 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Wes Devauld
|
3
|
+
#
|
4
|
+
# This library is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as
|
6
|
+
# published by the Free Software Foundation; either version 2.1 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful, but
|
10
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
17
|
+
# 02110-1301 USA
|
18
|
+
#
|
19
|
+
|
20
|
+
#
|
21
|
+
# Note that the :description field is particular to ib-ruby, and is NOT part of the standard TWS API.
|
22
|
+
# It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary string that
|
23
|
+
# you may find useful there.
|
24
|
+
#
|
25
|
+
|
26
|
+
module IB
|
27
|
+
module Symbols
|
28
|
+
Forex = {
|
29
|
+
:audusd => Datatypes::Contract.new({
|
30
|
+
:symbol => "AUD",
|
31
|
+
:exchange => "IDEALPRO",
|
32
|
+
:currency => "USD",
|
33
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
34
|
+
:description => "AUDUSD"
|
35
|
+
}),
|
36
|
+
:gbpusd => Datatypes::Contract.new({
|
37
|
+
:symbol => "GBP",
|
38
|
+
:exchange => "IDEALPRO",
|
39
|
+
:currency => "USD",
|
40
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
41
|
+
:description => "GBPUSD"
|
42
|
+
}),
|
43
|
+
|
44
|
+
:euraud => Datatypes::Contract.new({
|
45
|
+
:symbol => "EUR",
|
46
|
+
:exchange => "IDEALPRO",
|
47
|
+
:currency => "AUD",
|
48
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
49
|
+
:description => "EURAUD"
|
50
|
+
}),
|
51
|
+
|
52
|
+
:eurgbp => Datatypes::Contract.new({
|
53
|
+
:symbol => "EUR",
|
54
|
+
:exchange => "IDEALPRO",
|
55
|
+
:currency => "GBP",
|
56
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
57
|
+
:description => "EURGBP"
|
58
|
+
}),
|
59
|
+
|
60
|
+
:eurjpy => Datatypes::Contract.new({
|
61
|
+
:symbol => "EUR",
|
62
|
+
:exchange => "IDEALPRO",
|
63
|
+
:currency => "JPY",
|
64
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
65
|
+
:description => "EURJPY"
|
66
|
+
}),
|
67
|
+
|
68
|
+
:eurusd => Datatypes::Contract.new({
|
69
|
+
:symbol => "EUR",
|
70
|
+
:exchange => "IDEALPRO",
|
71
|
+
:currency => "USD",
|
72
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
73
|
+
:description => "EURUSD"
|
74
|
+
}),
|
75
|
+
|
76
|
+
:eurcad => Datatypes::Contract.new({
|
77
|
+
:symbol => "EUR",
|
78
|
+
:exchange => "IDEALPRO",
|
79
|
+
:currency => "CAD",
|
80
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
81
|
+
:description => "EURCAD"
|
82
|
+
}),
|
83
|
+
|
84
|
+
:usdchf => Datatypes::Contract.new({
|
85
|
+
:symbol => "USD",
|
86
|
+
:exchange => "IDEALPRO",
|
87
|
+
:currency => "CHF",
|
88
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
89
|
+
:description => "USDCHF"
|
90
|
+
}),
|
91
|
+
|
92
|
+
:usdcad => Datatypes::Contract.new({
|
93
|
+
:symbol => "USD",
|
94
|
+
:exchange => "IDEALPRO",
|
95
|
+
:currency => "CAD",
|
96
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
97
|
+
:description => "USDCAD"
|
98
|
+
}),
|
99
|
+
|
100
|
+
:usdjpy => Datatypes::Contract.new({
|
101
|
+
:symbol => "USD",
|
102
|
+
:exchange => "IDEALPRO",
|
103
|
+
:currency => "JPY",
|
104
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:forex],
|
105
|
+
:description => "USDJPY"
|
106
|
+
})
|
107
|
+
}
|
108
|
+
end # Contracts
|
109
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Wes Devauld
|
3
|
+
#
|
4
|
+
# This library is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Lesser General Public License as
|
6
|
+
# published by the Free Software Foundation; either version 2.1 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful, but
|
10
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
17
|
+
# 02110-1301 USA
|
18
|
+
#
|
19
|
+
|
20
|
+
|
21
|
+
# The Futures constant is currently for testing purposes. It guesses the front month
|
22
|
+
# currency future using a crude algorithm that does not take into account expiry/rollover day.
|
23
|
+
# This will be valid most of the time, but near/after expiry day the next quarter's contract
|
24
|
+
# takes over as the volume leader.
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# Note that the :description field is particular to ib-ruby, and is NOT part of the standard TWS API.
|
28
|
+
# It is never transmitted to IB. It's purely used clientside, and you can store any arbitrary string that
|
29
|
+
# you may find useful there.
|
30
|
+
#
|
31
|
+
|
32
|
+
module IB
|
33
|
+
module Symbols
|
34
|
+
|
35
|
+
# Get the next valid quarter month >= today, for finding the
|
36
|
+
# front month of quarterly futures.
|
37
|
+
#
|
38
|
+
# N.B. This will not work as expected near/after expiration during that month, as
|
39
|
+
# volume rolls over to the next quarter even though the current month is still valid!
|
40
|
+
#
|
41
|
+
|
42
|
+
|
43
|
+
def self.next_quarter_month(time)
|
44
|
+
sprintf("%02d", [3, 6, 9, 12].find{|month| month >= time.month })
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.next_quarter_year(time)
|
48
|
+
if self.next_quarter_month(time).to_i < time.month
|
49
|
+
time.year + 1
|
50
|
+
else
|
51
|
+
time.year
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.next_expiry(time)
|
56
|
+
"#{ self.next_quarter_year(time) }#{ self.next_quarter_month(time) }"
|
57
|
+
end
|
58
|
+
|
59
|
+
Futures =
|
60
|
+
{
|
61
|
+
:es => Datatypes::Contract.new({
|
62
|
+
:symbol => "ES",
|
63
|
+
:expiry => self.next_expiry(Time.now),
|
64
|
+
:exchange => "GLOBEX",
|
65
|
+
:currency => "USD",
|
66
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:future],
|
67
|
+
:multiplier => 50,
|
68
|
+
:description => "E-Mini S&P 500"
|
69
|
+
}),
|
70
|
+
|
71
|
+
:gbp => Datatypes::Contract.new({
|
72
|
+
:symbol => "GBP",
|
73
|
+
:expiry => self.next_expiry(Time.now),
|
74
|
+
:exchange => "GLOBEX",
|
75
|
+
:currency => "USD",
|
76
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:future],
|
77
|
+
:multiplier => 62500,
|
78
|
+
:description => "British Pounds"
|
79
|
+
}),
|
80
|
+
:eur => Datatypes::Contract.new({
|
81
|
+
:symbol => "EUR",
|
82
|
+
:expiry => self.next_expiry(Time.now),
|
83
|
+
:exchange => "GLOBEX",
|
84
|
+
:currency => "USD",
|
85
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:future],
|
86
|
+
:multiplier => 12500,
|
87
|
+
:description => "Euro FX"
|
88
|
+
}),
|
89
|
+
:jpy => Datatypes::Contract.new({
|
90
|
+
:symbol => "JPY",
|
91
|
+
:expiry => self.next_expiry(Time.now),
|
92
|
+
:exchange => "GLOBEX",
|
93
|
+
:currency => "USD",
|
94
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:future],
|
95
|
+
:multiplier => 12500000,
|
96
|
+
:description => "Japanese Yen"
|
97
|
+
}),
|
98
|
+
:hsi => Datatypes::Contract.new({
|
99
|
+
:symbol => "HSI",
|
100
|
+
:expiry => self.next_expiry(Time.now),
|
101
|
+
:exchange => "HKFE",
|
102
|
+
:currency => "HKD",
|
103
|
+
:sec_type => Datatypes::Contract::SECURITY_TYPES[:future],
|
104
|
+
:multiplier => 50,
|
105
|
+
:description => "Hang Seng Index"
|
106
|
+
})
|
107
|
+
}
|
108
|
+
end
|
109
|
+
end
|
data/lib/ib-ruby.rb
ADDED
data/lib/version.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
|
3
|
+
describe IB::Datatypes::Contract do
|
4
|
+
|
5
|
+
it 'instantiates without options' do
|
6
|
+
x = IB::Datatypes::Contract.new
|
7
|
+
x.should_not be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'allows setting attributes' do
|
11
|
+
expect {
|
12
|
+
x = IB::Datatypes::Contract.new
|
13
|
+
x.symbol = "TEST"
|
14
|
+
x.sec_type = IB::Datatypes::Contract::SECURITY_TYPES[:stock]
|
15
|
+
x.expiry = 200609
|
16
|
+
x.strike = 1234
|
17
|
+
x.right = "put"
|
18
|
+
x.multiplier = 123
|
19
|
+
x.exchange = "SMART"
|
20
|
+
x.currency = "USD"
|
21
|
+
x.local_symbol = "baz"
|
22
|
+
}.to_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises on wrong security type' do
|
26
|
+
expect {
|
27
|
+
x = IB::Datatypes::Contract.new({:sec_type => "asdf"})
|
28
|
+
}.to raise_error ArgumentError
|
29
|
+
|
30
|
+
expect {
|
31
|
+
x = IB::Datatypes::Contract.new
|
32
|
+
x.sec_type = "asdf"
|
33
|
+
}.to raise_error ArgumentError
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'accepts pre-determined security types' do
|
38
|
+
IB::Datatypes::Contract::SECURITY_TYPES.values.each do |type|
|
39
|
+
expect {
|
40
|
+
x = IB::Datatypes::Contract.new({:sec_type => type})
|
41
|
+
}.to_not raise_error
|
42
|
+
|
43
|
+
expect {
|
44
|
+
x = IB::Datatypes::Contract.new
|
45
|
+
x.sec_type = type
|
46
|
+
}.to_not raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises on wrong expiry' do
|
51
|
+
expect {
|
52
|
+
x = IB::Datatypes::Contract.new({:expiry => "foo"})
|
53
|
+
}.to raise_error ArgumentError
|
54
|
+
|
55
|
+
expect {
|
56
|
+
x = IB::Datatypes::Contract.new
|
57
|
+
x.expiry = "foo"
|
58
|
+
}.to raise_error ArgumentError
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'accepts correct expiry' do
|
62
|
+
expect {
|
63
|
+
x = IB::Datatypes::Contract.new({:expiry => "200607"})
|
64
|
+
}.to_not raise_error
|
65
|
+
|
66
|
+
expect {
|
67
|
+
x = IB::Datatypes::Contract.new
|
68
|
+
x.expiry = "200607"
|
69
|
+
}.to_not raise_error
|
70
|
+
|
71
|
+
expect {
|
72
|
+
x = IB::Datatypes::Contract.new({:expiry => 200607})
|
73
|
+
}.to_not raise_error
|
74
|
+
|
75
|
+
expect {
|
76
|
+
x = IB::Datatypes::Contract.new
|
77
|
+
x.expiry = 200607
|
78
|
+
x.expiry.should == "200607" # converted to a string
|
79
|
+
}.to_not raise_error
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'raises on incorrect right (option type)' do
|
84
|
+
expect {
|
85
|
+
x = IB::Datatypes::Contract.new({:right => "foo"})
|
86
|
+
}.to raise_error ArgumentError
|
87
|
+
expect {
|
88
|
+
x = IB::Datatypes::Contract.new
|
89
|
+
x.right = "foo"
|
90
|
+
}.to raise_error ArgumentError
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'accepts all correct values for right (option type)' do
|
94
|
+
["PUT", "put", "P", "p", "CALL", "call", "C", "c"].each do |right|
|
95
|
+
expect {
|
96
|
+
x = IB::Datatypes::Contract.new({:right => right})
|
97
|
+
}.to_not raise_error
|
98
|
+
|
99
|
+
expect {
|
100
|
+
x = IB::Datatypes::Contract.new
|
101
|
+
x.right = right
|
102
|
+
}.to_not raise_error
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "serialization" do
|
107
|
+
let(:stock) do
|
108
|
+
stock = IB::Datatypes::Contract.new
|
109
|
+
stock.symbol = "TEST"
|
110
|
+
stock.sec_type = IB::Datatypes::Contract::SECURITY_TYPES[:stock]
|
111
|
+
stock.expiry = 200609
|
112
|
+
stock.strike = 1234
|
113
|
+
stock.right = "put"
|
114
|
+
stock.multiplier = 123
|
115
|
+
stock.exchange = "SMART"
|
116
|
+
stock.currency = "USD"
|
117
|
+
stock.local_symbol = "baz"
|
118
|
+
stock
|
119
|
+
end
|
120
|
+
|
121
|
+
it "serializes long" do
|
122
|
+
stock.serialize_long(20).should ==
|
123
|
+
["TEST", IB::Datatypes::Contract::SECURITY_TYPES[:stock], "200609", 1234, "PUT", 123, "SMART", nil, "USD", "baz"]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "serializes short" do
|
127
|
+
stock.serialize_short(20).should ==
|
128
|
+
["TEST", IB::Datatypes::Contract::SECURITY_TYPES[:stock], "200609", 1234, "PUT", 123, "SMART", "USD", "baz"]
|
129
|
+
end
|
130
|
+
end #serialization
|
131
|
+
end # describe IB::Datatypes::Contract
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.expand_path(
|
2
|
+
File.join(File.dirname(__FILE__), %w[.. lib ib-ruby]))
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
# config.exclusion_filter = { :slow => true }
|
6
|
+
# config.filter = { :focus => true }
|
7
|
+
# config.include(UserExampleHelpers)
|
8
|
+
# config.mock_with :mocha
|
9
|
+
# config.mock_with :flexmock
|
10
|
+
# config.mock_with :rr
|
11
|
+
end
|
data/tasks/common.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#task :default => 'test:run'
|
2
|
+
#task 'gem:release' => 'test:run'
|
3
|
+
|
4
|
+
task :notes do
|
5
|
+
puts 'Output annotations (TBD)'
|
6
|
+
end
|
7
|
+
|
8
|
+
#Bundler not ready for prime time just yet
|
9
|
+
#desc 'Bundle dependencies'
|
10
|
+
#task :bundle do
|
11
|
+
# output = `bundle check 2>&1`
|
12
|
+
#
|
13
|
+
# unless $?.to_i == 0
|
14
|
+
# puts output
|
15
|
+
# system "bundle install"
|
16
|
+
# puts
|
17
|
+
# end
|
18
|
+
#end
|
data/tasks/doc.rake
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
desc 'Alias to doc:rdoc'
|
2
|
+
task :doc => 'doc:rdoc'
|
3
|
+
|
4
|
+
namespace :doc do
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
Rake::RDocTask.new do |rdoc|
|
7
|
+
# Rake::RDocTask.new(:rdoc => "rdoc", :clobber_rdoc => "clobber", :rerdoc => "rerdoc") do |rdoc|
|
8
|
+
rdoc.rdoc_dir = DOC_PATH.basename.to_s
|
9
|
+
rdoc.title = "#{NAME} #{CLASS_NAME::VERSION} Documentation"
|
10
|
+
rdoc.main = "README.doc"
|
11
|
+
rdoc.rdoc_files.include('README*')
|
12
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
13
|
+
end
|
14
|
+
end
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
desc "Alias to gem:release"
|
2
|
+
task :release => 'gem:release'
|
3
|
+
|
4
|
+
desc "Alias to gem:install"
|
5
|
+
task :install => 'gem:install'
|
6
|
+
|
7
|
+
desc "Alias to gem:build"
|
8
|
+
task :gem => 'gem:build'
|
9
|
+
|
10
|
+
namespace :gem do
|
11
|
+
gem_file = "#{NAME}-#{CLASS_NAME::VERSION}.gem"
|
12
|
+
|
13
|
+
desc "(Re-)Build gem"
|
14
|
+
task :build do
|
15
|
+
puts "Remove existing gem package"
|
16
|
+
rm_rf PKG_PATH
|
17
|
+
puts "Build new gem package"
|
18
|
+
system "gem build #{NAME}.gemspec"
|
19
|
+
puts "Move built gem to package dir"
|
20
|
+
mkdir_p PKG_PATH
|
21
|
+
mv gem_file, PKG_PATH
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Cleanup already installed gem(s)"
|
25
|
+
task :cleanup do
|
26
|
+
puts "Cleaning up installed gem(s)"
|
27
|
+
system "gem cleanup #{NAME}"
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build and install gem"
|
31
|
+
task :install => :build do
|
32
|
+
system "gem install #{PKG_PATH}/#{gem_file}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Build and push gem to Gemcutter"
|
36
|
+
task :release => [:build, 'git:tag'] do
|
37
|
+
puts "Pushing gem to Gemcutter"
|
38
|
+
system "gem push #{PKG_PATH}/#{gem_file}"
|
39
|
+
end
|
40
|
+
end
|
data/tasks/git.rake
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
desc "Alias to git:commit"
|
2
|
+
task :git => 'git:commit'
|
3
|
+
|
4
|
+
namespace :git do
|
5
|
+
|
6
|
+
desc "Stage and commit your work [with message]"
|
7
|
+
task :commit, [:message] do |t, args|
|
8
|
+
puts "Staging new (unversioned) files"
|
9
|
+
system "git add --all"
|
10
|
+
if args.message
|
11
|
+
puts "Committing with message: #{args.message}"
|
12
|
+
system %Q[git commit -a -m "#{args.message}" --author arvicco]
|
13
|
+
else
|
14
|
+
puts "Committing"
|
15
|
+
system %Q[git commit -a -m "No message" --author arvicco]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Push local changes to Github"
|
20
|
+
task :push => :commit do
|
21
|
+
puts "Pushing local changes to remote"
|
22
|
+
system "git push"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Create (release) tag on Github"
|
26
|
+
task :tag => :push do
|
27
|
+
tag = CLASS_NAME::VERSION
|
28
|
+
puts "Creating git tag: #{tag}"
|
29
|
+
system %Q{git tag -a -m "Release tag #{tag}" #{tag}}
|
30
|
+
puts "Pushing #{tag} to remote"
|
31
|
+
system "git push origin #{tag}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
desc 'Alias to spec:spec'
|
2
|
+
task :spec => 'spec:spec'
|
3
|
+
|
4
|
+
namespace :spec do
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
desc "Run all specs"
|
8
|
+
RSpec::Core::RakeTask.new(:spec) { |task|}
|
9
|
+
|
10
|
+
desc "Run specs with RCov"
|
11
|
+
RSpec::Core::RakeTask.new(:rcov) do |task|
|
12
|
+
task.rcov = true
|
13
|
+
task.rcov_opts = ['--exclude', 'spec']
|
14
|
+
end
|
15
|
+
end
|
data/tasks/version.rake
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class Version
|
2
|
+
attr_accessor :major, :minor, :patch, :build
|
3
|
+
|
4
|
+
def initialize(version_string)
|
5
|
+
raise "Invalid version #{version_string}" unless version_string =~ /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/
|
6
|
+
@major = $1.to_i
|
7
|
+
@minor = $2.to_i
|
8
|
+
@patch = $3.to_i
|
9
|
+
@build = $4
|
10
|
+
end
|
11
|
+
|
12
|
+
def bump_major(x)
|
13
|
+
@major += x.to_i
|
14
|
+
@minor = 0
|
15
|
+
@patch = 0
|
16
|
+
@build = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def bump_minor(x)
|
20
|
+
@minor += x.to_i
|
21
|
+
@patch = 0
|
22
|
+
@build = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def bump_patch(x)
|
26
|
+
@patch += x.to_i
|
27
|
+
@build = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(major, minor, patch, build=nil)
|
31
|
+
@major = major
|
32
|
+
@minor = minor
|
33
|
+
@patch = patch
|
34
|
+
@build = build
|
35
|
+
end
|
36
|
+
|
37
|
+
def write(desc = nil)
|
38
|
+
CLASS_NAME::VERSION_FILE.open('w') { |file| file.puts to_s }
|
39
|
+
(BASE_PATH + 'HISTORY').open('a') do |file|
|
40
|
+
file.puts "\n== #{to_s} / #{Time.now.strftime '%Y-%m-%d'}\n"
|
41
|
+
file.puts "\n* #{desc}\n" if desc
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
[major, minor, patch, build].compact.join('.')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Set version: [x.y.z] - explicitly, [1/10/100] - bump major/minor/patch, [.build] - build'
|
51
|
+
task :version, [:command, :desc] do |t, args|
|
52
|
+
version = Version.new(CLASS_NAME::VERSION)
|
53
|
+
case args.command
|
54
|
+
when /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/ # Set version explicitly
|
55
|
+
version.update($1, $2, $3, $4)
|
56
|
+
when /^\.(.*?)$/ # Set build
|
57
|
+
version.build = $1
|
58
|
+
when /^(\d{1})$/ # Bump patch
|
59
|
+
version.bump_patch $1
|
60
|
+
when /^(\d{1})0$/ # Bump minor
|
61
|
+
version.bump_minor $1
|
62
|
+
when /^(\d{1})00$/ # Bump major
|
63
|
+
version.bump_major $1
|
64
|
+
else # Unknown command, just display VERSION
|
65
|
+
puts "#{NAME} #{version}"
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "Writing version #{version} to VERSION file"
|
70
|
+
version.write args.desc
|
71
|
+
end
|