quandl 0.2.22
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 +15 -0
- data/.gitignore +16 -0
- data/.travis.yml +20 -0
- data/Gemfile +14 -0
- data/Guardfile +8 -0
- data/LICENSE +7 -0
- data/README.md +316 -0
- data/Rakefile +39 -0
- data/UPGRADE.md +143 -0
- data/bin/quandl +26 -0
- data/dist/resources/pkg/Distribution.erb +15 -0
- data/dist/resources/pkg/PackageInfo.erb +6 -0
- data/dist/resources/pkg/postinstall +45 -0
- data/dist/resources/pkg/quandl +25 -0
- data/dist/resources/ruby/PackageInfo +3 -0
- data/lib/commander/command/quandl_ext.rb +21 -0
- data/lib/quandl/command.rb +45 -0
- data/lib/quandl/command/client_ext.rb +1 -0
- data/lib/quandl/command/client_ext/user.rb +11 -0
- data/lib/quandl/command/compatibility_check.rb +11 -0
- data/lib/quandl/command/qconfig.rb +76 -0
- data/lib/quandl/command/tasks.rb +15 -0
- data/lib/quandl/command/tasks/base.rb +263 -0
- data/lib/quandl/command/tasks/delete.rb +58 -0
- data/lib/quandl/command/tasks/download.rb +111 -0
- data/lib/quandl/command/tasks/info.rb +46 -0
- data/lib/quandl/command/tasks/list.rb +40 -0
- data/lib/quandl/command/tasks/login.rb +46 -0
- data/lib/quandl/command/tasks/update.rb +205 -0
- data/lib/quandl/command/tasks/upload.rb +69 -0
- data/lib/quandl/command/version.rb +5 -0
- data/lib/quandl/utility.rb +2 -0
- data/lib/quandl/utility/config.rb +43 -0
- data/lib/quandl/utility/ruby_version.rb +143 -0
- data/quandl.gemspec +39 -0
- data/scripts/compile_ruby_pkg.sh +34 -0
- data/scripts/install.sh +51 -0
- data/scripts/win/quandl_toolbelt.iss +82 -0
- data/spec/lib/quandl/command/delete_spec.rb +31 -0
- data/spec/lib/quandl/command/download_spec.rb +42 -0
- data/spec/lib/quandl/command/upload_spec.rb +39 -0
- data/spec/lib/quandl/command_spec.rb +46 -0
- data/spec/spec_helper.rb +20 -0
- data/tasks/toolbelt.rake +133 -0
- data/tasks/toolbelt.rb +92 -0
- data/tasks/toolbelt/build.rb +2 -0
- data/tasks/toolbelt/build/darwin.rb +71 -0
- data/tasks/toolbelt/build/ruby.rb +105 -0
- data/tasks/toolbelt/build/tarball.rb +73 -0
- data/tasks/toolbelt/build/windows.rb +25 -0
- data/tasks/toolbelt/push.rb +15 -0
- data/tasks/toolbelt/storage.rb +28 -0
- data/tasks/toolbelt/tar.rb +21 -0
- metadata +354 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
class Quandl::Command::Tasks::Info < Quandl::Command::Tasks::Base
|
2
|
+
|
3
|
+
description "Display information about the Quandl Toolbelt."
|
4
|
+
|
5
|
+
def execute
|
6
|
+
info title "Quandl Toolbelt"
|
7
|
+
info current_user.info
|
8
|
+
info toolbelt_info
|
9
|
+
|
10
|
+
debug title "Package Versions"
|
11
|
+
debug package_info
|
12
|
+
end
|
13
|
+
|
14
|
+
def title(name)
|
15
|
+
name = name.to_s
|
16
|
+
"\n#{name}\n" + ( name.length.times.collect{'='}.join )
|
17
|
+
end
|
18
|
+
|
19
|
+
def user_info
|
20
|
+
[
|
21
|
+
"username: #{current_user.username}",
|
22
|
+
"email: #{current_user.email}",
|
23
|
+
].join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def toolbelt_info
|
27
|
+
[
|
28
|
+
"host: #{quandl_url}",
|
29
|
+
"token: #{auth_token}",
|
30
|
+
"version: #{Quandl::Command::VERSION}",
|
31
|
+
].join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def package_info
|
35
|
+
quandl_package_versions.sort_by{|p| p[:package].to_s }.collect{|p| "#{ p[:package] } ( #{ p[:version] } )" }.join("\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
def quandl_package_versions
|
39
|
+
Quandl.constants.collect do |c|
|
40
|
+
package = "Quandl::#{c}".constantize
|
41
|
+
version = "Quandl::#{c}::VERSION".constantize rescue nil
|
42
|
+
{ package: package, version: version } unless version.nil?
|
43
|
+
end.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Quandl::Command::Tasks::List < Quandl::Command::Tasks::Base
|
2
|
+
|
3
|
+
description "List datasets matching conditions."
|
4
|
+
options({
|
5
|
+
String => {
|
6
|
+
match: "Only return datasets matching: [match]",
|
7
|
+
source_code: "Return datasets matching: [SOURCE_CODE]"
|
8
|
+
},
|
9
|
+
Integer => {
|
10
|
+
limit: "How datasets to return per page.",
|
11
|
+
page: "Return datasets starting from: [page]",
|
12
|
+
}
|
13
|
+
})
|
14
|
+
|
15
|
+
authenticated_users_only!
|
16
|
+
|
17
|
+
def execute
|
18
|
+
# find dataset
|
19
|
+
debug "search_params: #{search_params}"
|
20
|
+
dataset = Quandl::Client::Dataset.where( search_params ).fetch
|
21
|
+
codes = dataset.collect(&:full_code)
|
22
|
+
# fail on errors
|
23
|
+
info codes.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def search_params
|
27
|
+
search_params = {}
|
28
|
+
search_params[:query] = options.match if options.match.present?
|
29
|
+
search_params[:source_code] = options.source_code.to_s.upcase if options.source_code.present?
|
30
|
+
search_params[:per_page] = options.limit if options.limit.present?
|
31
|
+
search_params[:page] = page
|
32
|
+
search_params[:self_search] = search_params[:source_code].present? ? false : true
|
33
|
+
search_params
|
34
|
+
end
|
35
|
+
|
36
|
+
def page
|
37
|
+
options.page.to_i || 1
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Quandl::Command::Tasks::Login < Quandl::Command::Tasks::Base
|
2
|
+
|
3
|
+
description "Login to quandl with username and email."
|
4
|
+
|
5
|
+
options String => { method: 'Login method? ( password | token )' }
|
6
|
+
|
7
|
+
def execute
|
8
|
+
authenticate!
|
9
|
+
reload_session!
|
10
|
+
if current_user.present?
|
11
|
+
info "You have successfully authenticated!"
|
12
|
+
info current_user.info
|
13
|
+
else
|
14
|
+
error "Failed to authenticate!"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate!
|
19
|
+
return execute_password_login if options.method == 'password'
|
20
|
+
execute_token_login
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute_token_login
|
24
|
+
info("Obtain your Auth Token from this page: http://www.quandl.com/users/info")
|
25
|
+
token = ask("Auth Token: "){ |q| q.echo = "*" }
|
26
|
+
write_auth_token(token)
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute_password_login
|
30
|
+
# request login and password
|
31
|
+
login = ask("Username or Email: ")
|
32
|
+
password = ask("Password: "){ |q| q.echo = "*" }
|
33
|
+
# attempt to login
|
34
|
+
user = Quandl::Client::User.login( login: login, password: password )
|
35
|
+
# fail on errors
|
36
|
+
return error( user.human_status ) unless user.auth_token.present?
|
37
|
+
# output qdf
|
38
|
+
write_auth_token(user.auth_token)
|
39
|
+
info "You've successfully authorized #{login}!"
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_auth_token(token)
|
43
|
+
QConfig.configuration.token = token
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
class Quandl::Command::Tasks::Update < Quandl::Command::Tasks::Base
|
2
|
+
|
3
|
+
# curl -s https://s3.amazonaws.com/quandl-command/install.sh | bash
|
4
|
+
|
5
|
+
description "Update Quandl Toolbelt to the latest version."
|
6
|
+
syntax %Q{quandl update [revision]
|
7
|
+
|
8
|
+
Examples:
|
9
|
+
|
10
|
+
$ quandl update
|
11
|
+
Updating from 0.2.18 ...
|
12
|
+
You are up to date! ( 0.3.1 )
|
13
|
+
|
14
|
+
$ quandl update beta1
|
15
|
+
Updating from 0.3.1 ...
|
16
|
+
You are up to date! ( 0.3.1-beta1 )}
|
17
|
+
|
18
|
+
PACKAGE_URL = 'http://s3.amazonaws.com/quandl-command/'
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def package_url(revision=nil)
|
22
|
+
# are we on windows?
|
23
|
+
platform = Quandl::Utility::Config.windows? ? 'windows' : nil
|
24
|
+
# build filename
|
25
|
+
filename = ['quandl-command', platform, revision, 'tar.gz'].compact.join(".")
|
26
|
+
# append s3 url
|
27
|
+
File.join(PACKAGE_URL, filename)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
# load libraries needed by this action
|
33
|
+
require_dependencies
|
34
|
+
return unless assert_update_requirements!
|
35
|
+
info "Updating from #{Quandl::Command::VERSION} ... "
|
36
|
+
# wipe update/ and backup/ folders
|
37
|
+
prepare_for_update
|
38
|
+
download_tarball
|
39
|
+
# ensure package was downloaded
|
40
|
+
return error("'#{package_url}' not found") unless File.exists?(tarball_path)
|
41
|
+
# install
|
42
|
+
extract_tarball
|
43
|
+
copy_windows_specific_files if Quandl::Utility::Config.windows?
|
44
|
+
install_update
|
45
|
+
configure_update
|
46
|
+
ensure_correct_permissions
|
47
|
+
# success
|
48
|
+
version = %x{quandl -v}.to_s.strip.rstrip
|
49
|
+
info "You are up to date! ( #{version} )"
|
50
|
+
|
51
|
+
rescue => err
|
52
|
+
# log error
|
53
|
+
error(err)
|
54
|
+
debug(err.backtrace.join("\n"))
|
55
|
+
# report failure and rollback
|
56
|
+
info("----\nAn error has occured! Rolling back to previous version ... ")
|
57
|
+
info("If the problem persists reinstall with: #{installer_url}")
|
58
|
+
rollback_update
|
59
|
+
end
|
60
|
+
|
61
|
+
def installer_url
|
62
|
+
return File.join(PACKAGE_URL, "Quandl Setup.exe") if Quandl::Utility::Config.windows?
|
63
|
+
return File.join(PACKAGE_URL, "quandl-toolbelt.pkg") if Quandl::Utility::Config.macosx?
|
64
|
+
end
|
65
|
+
|
66
|
+
def package_path
|
67
|
+
@package_path ||= File.join(update_path, "quandl-command")
|
68
|
+
end
|
69
|
+
|
70
|
+
def tarball_path
|
71
|
+
@tarball_path ||= File.join(update_path, "update.tar.gz")
|
72
|
+
end
|
73
|
+
|
74
|
+
def package_url
|
75
|
+
@package_url ||= self.class.package_url(args.first)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_path
|
79
|
+
@update_path ||= File.join( root_path, 'update' )
|
80
|
+
end
|
81
|
+
|
82
|
+
def backup_path
|
83
|
+
@backup_path ||= File.join( root_path, 'backup' )
|
84
|
+
end
|
85
|
+
|
86
|
+
def root_path
|
87
|
+
Quandl::Command::Tasks.root
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def require_dependencies
|
94
|
+
require 'quandl/utility/config'
|
95
|
+
require 'zlib'
|
96
|
+
require 'archive/tar/minitar'
|
97
|
+
end
|
98
|
+
|
99
|
+
def assert_update_requirements!
|
100
|
+
return fatal("update is destructive and disabled in development!") if Dir.exists?(File.join(root_path, ".git"))
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def prepare_for_update
|
105
|
+
[backup_path, update_path].each do |path|
|
106
|
+
# remove previous directory if present
|
107
|
+
rm_rf(path) if Dir.exists?(path)
|
108
|
+
# create new directory
|
109
|
+
mkdir_p(path) unless Dir.exists?(path)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def download_tarball
|
114
|
+
debug "Downloading '#{package_url}' to '#{tarball_path}'"
|
115
|
+
# download new package
|
116
|
+
uri = URI( package_url )
|
117
|
+
# open connection to storage host
|
118
|
+
Net::HTTP.start( uri.host, uri.port ) do |http|
|
119
|
+
# download file
|
120
|
+
resp = http.get( uri.path )
|
121
|
+
# write tar file if it was found
|
122
|
+
open( tarball_path, "wb"){|f| f.write(resp.body) } unless resp.code == '404'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def extract_tarball
|
127
|
+
debug "Archive::Tar::Minitar.unpack( '#{tarball_path}', '#{update_path}' )"
|
128
|
+
# extract into update_path
|
129
|
+
Archive::Tar::Minitar.unpack( Zlib::GzipReader.open(tarball_path), update_path )
|
130
|
+
end
|
131
|
+
|
132
|
+
def copy_windows_specific_files
|
133
|
+
files = ['bin/quandl.bat']
|
134
|
+
files.each do |file|
|
135
|
+
source_path = File.join(root_path, file)
|
136
|
+
cp source_path, File.join(package_path, file) if File.exists?(source_path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def install_update
|
141
|
+
debug "Installing '#{update_path}' to '#{root_path}'"
|
142
|
+
# install each folder into the live directory
|
143
|
+
Dir.glob(File.join(package_path, "/*")) do |update_dir|
|
144
|
+
# current folder
|
145
|
+
folder_name = File.basename(update_dir)
|
146
|
+
# get live dir
|
147
|
+
live_dir = File.join(root_path, folder_name )
|
148
|
+
# move live to backup (skip this step if it doesn't exist since it might be a new folder)
|
149
|
+
mv live_dir, File.join(backup_path, folder_name) if File.exists?(live_dir)
|
150
|
+
# move update to live
|
151
|
+
mv update_dir, live_dir
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def configure_update
|
156
|
+
if Dir.exists?("#{root_path}/ruby")
|
157
|
+
bin_file = File.read("#{root_path}/bin/quandl")
|
158
|
+
bin_file.gsub!("#!/usr/bin/env ruby", "#!/#{root_path}/ruby/bin/ruby")
|
159
|
+
File.write("#{root_path}/bin/quandl", bin_file)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def rollback_update
|
164
|
+
Dir.glob(File.join(backup_path, "/*")) do |backup_dir|
|
165
|
+
# current folder
|
166
|
+
folder_name = File.basename(backup_dir)
|
167
|
+
# get live dir
|
168
|
+
live_dir = File.join(root_path, folder_name )
|
169
|
+
# move live to update
|
170
|
+
mv live_dir, File.join(package_path, folder_name)
|
171
|
+
# move backup to live
|
172
|
+
mv backup_dir, live_dir
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def ensure_correct_permissions
|
177
|
+
chmod("+x", File.join(root_path, 'bin/quandl'))
|
178
|
+
end
|
179
|
+
|
180
|
+
def chmod(*args)
|
181
|
+
debug("FileUtils.chmod #{args.to_a.join(' ')}")
|
182
|
+
FileUtils.chmod(*args)
|
183
|
+
end
|
184
|
+
|
185
|
+
def cp(old_path, new_path)
|
186
|
+
debug("FileUtils.cp #{old_path} #{new_path}")
|
187
|
+
FileUtils.cp( old_path, new_path )
|
188
|
+
end
|
189
|
+
|
190
|
+
def mv(old_path, new_path)
|
191
|
+
debug("FileUtils.mv #{old_path} #{new_path}")
|
192
|
+
FileUtils.mv( old_path, new_path )
|
193
|
+
end
|
194
|
+
|
195
|
+
def rm_rf(*args)
|
196
|
+
debug( "FileUtils.rm_rf #{args.to_a.join(" ")}")
|
197
|
+
FileUtils.rm_rf(*args)
|
198
|
+
end
|
199
|
+
|
200
|
+
def mkdir_p(*args)
|
201
|
+
debug( "FileUtils.mkdir_p #{args.to_a.join(" ")}")
|
202
|
+
FileUtils.mkdir_p(*args)
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Quandl::Command::Tasks::Upload < Quandl::Command::Tasks::Base
|
2
|
+
|
3
|
+
description "Upload a dataset using its quandl code."
|
4
|
+
syntax %{quandl upload file.qdf
|
5
|
+
|
6
|
+
Examples:
|
7
|
+
|
8
|
+
$ quandl upload file.qcsv
|
9
|
+
OK | 98ms | http://quandl.com/USERNAME/CODE_1
|
10
|
+
OK | 72ms | http://quandl.com/USERNAME/CODE_2
|
11
|
+
|
12
|
+
$ ruby code.rb | quandl upload
|
13
|
+
OK | 98ms | http://quandl.com/USERNAME/CODE_1
|
14
|
+
OK | 72ms | http://quandl.com/USERNAME/CODE_2
|
15
|
+
|
16
|
+
Quandl CSV Format:
|
17
|
+
|
18
|
+
code: YOUR_QUANDL_CODE
|
19
|
+
name: Dataset Title
|
20
|
+
description: Dataset description.
|
21
|
+
private: false
|
22
|
+
-
|
23
|
+
Date, First, Second, Third
|
24
|
+
2013-11-22,1252.0,454.95,448.2
|
25
|
+
2013-11-21,452.25,457.75,449.1
|
26
|
+
}
|
27
|
+
options({
|
28
|
+
Integer => {
|
29
|
+
threads: "How many workers to use during download.",
|
30
|
+
}
|
31
|
+
})
|
32
|
+
|
33
|
+
authenticated_users_only!
|
34
|
+
|
35
|
+
def execute
|
36
|
+
# datasets from file_path if given
|
37
|
+
interface = file_path.present? ? File.open(file_path, "r") : $stdin
|
38
|
+
# for each dataset streamed from interface
|
39
|
+
Quandl::Format::Dataset.each_line(interface) do |dataset|
|
40
|
+
pool.process{ upload( dataset ) }
|
41
|
+
end
|
42
|
+
pool.shutdown
|
43
|
+
end
|
44
|
+
|
45
|
+
def upload(dataset)
|
46
|
+
# display debug info when verbose
|
47
|
+
debug dataset.attributes.to_s
|
48
|
+
# upload
|
49
|
+
dataset.upload if dataset.valid?
|
50
|
+
# output report to $stdout or $stderr
|
51
|
+
report(dataset)
|
52
|
+
end
|
53
|
+
|
54
|
+
def report(dataset)
|
55
|
+
if [200,201].include?( dataset.client.status )
|
56
|
+
info table dataset.client.human_status,
|
57
|
+
dataset.client.elapsed_request_time_ms,
|
58
|
+
dataset.client.full_url
|
59
|
+
else
|
60
|
+
error(dataset.human_errors)
|
61
|
+
end
|
62
|
+
debug "---"
|
63
|
+
end
|
64
|
+
|
65
|
+
def file_path
|
66
|
+
args.first
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module Quandl::Utility
|
4
|
+
module Config
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def windows?
|
8
|
+
host_os == :windows
|
9
|
+
end
|
10
|
+
|
11
|
+
def macosx?
|
12
|
+
host_os == :macosx
|
13
|
+
end
|
14
|
+
|
15
|
+
def linux?
|
16
|
+
host_os == :linux
|
17
|
+
end
|
18
|
+
|
19
|
+
def unix?
|
20
|
+
host_os == :unix
|
21
|
+
end
|
22
|
+
|
23
|
+
def host_os
|
24
|
+
@os ||= (
|
25
|
+
host_os = RbConfig::CONFIG['host_os']
|
26
|
+
case host_os
|
27
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
28
|
+
:windows
|
29
|
+
when /darwin|mac os/
|
30
|
+
:macosx
|
31
|
+
when /linux/
|
32
|
+
:linux
|
33
|
+
when /solaris|bsd/
|
34
|
+
:unix
|
35
|
+
else
|
36
|
+
raise Error::WebDriverError, "unknown os: #{host_os.inspect}"
|
37
|
+
end
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|