quandl 0.3.0 → 0.3.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.
- checksums.yaml +8 -8
- data/UPGRADE.md +18 -1
- data/VERSION +1 -1
- data/lib/quandl/command/presenter.rb +1 -0
- data/lib/quandl/command/presenter/helper.rb +19 -0
- data/lib/quandl/command/presenter/record.rb +2 -10
- data/lib/quandl/command/tasks/schedule.rb +77 -22
- data/lib/quandl/command/tasks/superset.rb +7 -0
- data/quandl.gemspec +5 -3
- data/scripts/win/quandl_toolbelt.iss +1 -0
- data/spec/lib/quandl/command/schedule_spec.rb +10 -45
- metadata +37 -8
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDYxNjY3NjA1NTU3NmFiZGFiM2Q3YWU4YWNjZjM3NGRhZjJhZjIwOQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MjdiZTc0M2UzOTczNjBiOTQxMDdkNTgwY2JmYWQ2OTAzYjc4YjFiNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZDIwYTk5YWY2ZGZmYWY2MjBmMTNiNWI5ZjI2MTEwMzUwNmY2YzY3ZGEzMjYy
|
10
|
+
ZDhkNWJlMGRmZDA2MDJhZjA5NjNlN2I1NmIzNzg4MjE2MmEzMDI5MTMyZDEy
|
11
|
+
MzZmOGQyMWZjMjE4NmJjMDViZjBjNjAxNzg0ODFmZGIyMTQyMzI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MDg4MjRmYTY0NDI5NmRlYzA4OGQxNTMzMWVmNWFhMGQ4M2QzODU1YThjMmVi
|
14
|
+
ODYyMDBjNDViYjgwZDg2ZmEwZDUzNjViMWY1ZDZjZjk1ZDIyOTU3YjFlN2Nj
|
15
|
+
OWQ1MjZlMmE0NzE4NDgwNTI5NWQyN2JlMzRiZjA5MWQzZTE5ZGM=
|
data/UPGRADE.md
CHANGED
@@ -1,4 +1,21 @@
|
|
1
|
-
## 0.3.
|
1
|
+
## 0.3.3
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
## 0.3.2
|
8
|
+
|
9
|
+
* QUGC-151 quandl superset upload --> quandl superset
|
10
|
+
* QUGC-140 if a source_code is given but does not exist, it should warn the user
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
## 0.3.1
|
16
|
+
* Added support for timed scheduling
|
17
|
+
|
18
|
+
## 0.3.0
|
2
19
|
|
3
20
|
* QUGC-132 Add thread_pool locking so that requests for the same dataset are not made in parallel
|
4
21
|
* QUGC-120 update Task::Threading to catch SIGINT and shutdown thread_pool. Second occurence of SIGINT will exit immediately.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.3
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Quandl
|
2
|
+
module Command
|
3
|
+
class Presenter
|
4
|
+
class << self
|
5
|
+
def pretty_errors(messages)
|
6
|
+
result = []
|
7
|
+
re = messages.delete(:response_errors) if messages.is_a?(Hash) && messages.has_key?(:response_errors)
|
8
|
+
re.each{|k,v| messages[k] = v } if re.present? && re.is_a?(Hash)
|
9
|
+
# format
|
10
|
+
messages.each do |k,v|
|
11
|
+
v = v.join(" & ") if v.respond_to?(:join)
|
12
|
+
result << "#{k}: #{v}"
|
13
|
+
end
|
14
|
+
result.join(", ")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -93,17 +93,9 @@ class Record
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def errors
|
96
|
-
result = []
|
97
96
|
messages = object.try(:error_messages) || []
|
98
|
-
# extract
|
99
|
-
|
100
|
-
re.each{|k,v| messages[k] = v } if re.present? && re.is_a?(Hash)
|
101
|
-
# format
|
102
|
-
messages.each do |k,v|
|
103
|
-
v = v.join(" & ") if v.respond_to?(:join)
|
104
|
-
result << "#{k}: #{v}"
|
105
|
-
end
|
106
|
-
result.join(", ")
|
97
|
+
# extract response errors
|
98
|
+
Presenter.pretty_errors(messages)
|
107
99
|
end
|
108
100
|
|
109
101
|
def docs?
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
|
2
|
-
|
2
|
+
|
3
|
+
before_execute :require_dependencies
|
3
4
|
autoload_quandl_client
|
4
5
|
authenticated_users_only!
|
5
6
|
|
@@ -17,40 +18,46 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
|
|
17
18
|
EXAMPLES:
|
18
19
|
|
19
20
|
$ quandl schedule add scraper.rb
|
20
|
-
You have successfully scheduled scraper.rb
|
21
|
+
You have successfully scheduled scraper.rb.
|
21
22
|
|
22
|
-
$ quandl schedule add scraper.rb --name weekly_scraper.rb --
|
23
|
-
You have successfully scheduled weekly-scraper.rb
|
23
|
+
$ quandl schedule add scraper.rb --name weekly_scraper.rb --at "7pm Monday"
|
24
|
+
You have successfully scheduled weekly-scraper.rb.
|
24
25
|
|
25
|
-
$ quandl schedule replace scraper.rb
|
26
|
-
You have successfully
|
26
|
+
$ quandl schedule replace scraper.rb --at "13:00"
|
27
|
+
You have successfully replaced scraper.rb}
|
27
28
|
|
28
29
|
options({
|
29
30
|
String => {
|
30
31
|
name: "The name used to reference your scraper in the quandl cloud.",
|
31
|
-
|
32
|
+
at: "Time to run your script in UTC timezone. e.g. '14:30','7pm Monday', 'friday 13:00'"
|
32
33
|
}
|
33
34
|
})
|
34
|
-
|
35
|
+
|
36
|
+
DAYS_OF_THE_WEEK = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
|
37
|
+
|
35
38
|
def list
|
36
|
-
|
39
|
+
scrapers.each { |x| script_info x}
|
37
40
|
end
|
38
41
|
|
39
42
|
def show
|
40
|
-
|
43
|
+
script_info scraper
|
41
44
|
end
|
42
45
|
|
43
46
|
def add
|
44
|
-
Quandl::Client::Scraper.create( name: name, scraper: args.first )
|
45
|
-
|
46
|
-
|
47
|
+
result=Quandl::Client::Scraper.create( name: name, scraper: args.first, schedule_at: cron_at)
|
48
|
+
if result.valid?
|
49
|
+
info("You have successfully scheduled '#{scraper.name}'.")
|
50
|
+
info("#{schedule_message}")
|
51
|
+
else
|
52
|
+
raise "#{Quandl::Command::Presenter.pretty_errors(result.errors.messages).to_s.gsub("\n", ' ')}"
|
53
|
+
end
|
47
54
|
end
|
48
55
|
|
49
56
|
def download
|
50
57
|
begin
|
51
58
|
require 'open-uri'
|
52
59
|
open( scraper.name, 'wb') do |file|
|
53
|
-
$stdout << open(scraper.scraper_url).read
|
60
|
+
$stdout << open(scraper.scraper_url, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
|
54
61
|
end
|
55
62
|
rescue => err
|
56
63
|
present err
|
@@ -61,25 +68,65 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
|
|
61
68
|
(info("'#{name}' does not exist "); return;) if scraper.blank?
|
62
69
|
info("You are about to delete '#{scraper.name}'")
|
63
70
|
return unless confirmed?
|
64
|
-
scraper.destroy if scraper.respond_to?(:destroy)
|
65
|
-
|
71
|
+
result=scraper.destroy if scraper.respond_to?(:destroy)
|
72
|
+
if result.valid?
|
73
|
+
info("You have successfully deleted '#{scraper.name}'")
|
74
|
+
else
|
75
|
+
raise "#{Quandl::Command::Presenter.pretty_errors(result.errors.messages).to_s.gsub("\n", ' ')}"
|
76
|
+
end
|
77
|
+
|
66
78
|
end
|
67
79
|
|
68
80
|
|
69
81
|
def replace
|
70
82
|
(info("'#{name}' does not exist "); return;) if scraper.blank?
|
83
|
+
cron_at #validate if cron format is valid before deleting scraper
|
71
84
|
info("You are about to replace '#{scraper.name}'")
|
72
85
|
return unless confirmed?
|
73
|
-
scraper.
|
74
|
-
|
75
|
-
|
76
|
-
|
86
|
+
scraper.scraper = args.first
|
87
|
+
scraper.schedule_at = cron_at
|
88
|
+
scraper.save
|
89
|
+
if scraper.valid?
|
90
|
+
info("You have successfully replaced '#{scraper.name}'.")
|
91
|
+
info("#{schedule_message}")
|
92
|
+
else
|
93
|
+
raise "#{Quandl::Command::Presenter.pretty_errors(scraper.errors.messages).to_s.gsub("\n", ' ')}"
|
94
|
+
|
95
|
+
end
|
77
96
|
end
|
78
97
|
|
79
98
|
private
|
80
99
|
|
100
|
+
def require_dependencies
|
101
|
+
require 'chronic'
|
102
|
+
require 'whedon'
|
103
|
+
end
|
104
|
+
|
105
|
+
def script_info(script)
|
106
|
+
unless script.schedule_at.empty?
|
107
|
+
info("#{(script.name+'.').ljust(20)} Scheduled: #{script_run_time(script.schedule_at)}")
|
108
|
+
else
|
109
|
+
info("#{(script.name+'.').ljust(20)} Scheduled: 3 times a day")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def script_run_time(cron_time)
|
115
|
+
"every #{cron_time.ends_with?('*') ? 'day' : DAYS_OF_THE_WEEK[cron_time[-1].to_i]} at #{script_next_run(cron_time).strftime("%H:%M (UTC)")}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def script_next_run(cron_time)
|
119
|
+
Whedon::Schedule.new(cron_time).next
|
120
|
+
end
|
121
|
+
|
122
|
+
|
81
123
|
def schedule_message
|
82
|
-
|
124
|
+
if options.at
|
125
|
+
"Your script first run will happen #{script_next_run(cron_at).strftime("on %d %B at %H:%M (UTC)")}. It will continue to run #{script_run_time(cron_at)}
|
126
|
+
Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
|
127
|
+
else
|
128
|
+
"It will run 3 times a day starting immediately.\n Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
|
129
|
+
end
|
83
130
|
end
|
84
131
|
|
85
132
|
def scrapers
|
@@ -97,7 +144,15 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
|
|
97
144
|
# find the scraper with the id
|
98
145
|
Quandl::Client::Scraper.find(id) unless id.nil?
|
99
146
|
end
|
100
|
-
|
147
|
+
|
148
|
+
def cron_at
|
149
|
+
return nil unless options.at
|
150
|
+
time_value=Chronic.parse(options.at)
|
151
|
+
raise "#{options.at} is invalid time" if time_value.nil?
|
152
|
+
day_of_the_week = options.at =~ (/Mon|Tue|Wed|Thu|Fri|Sat|Sun/i) ? time_value.wday : '*'
|
153
|
+
"#{time_value.min} #{time_value.hour} * * #{day_of_the_week}"
|
154
|
+
end
|
155
|
+
|
101
156
|
def name
|
102
157
|
return options.name if options.name.present?
|
103
158
|
return File.basename(args.first) if args.first.present?
|
@@ -14,6 +14,13 @@ class Quandl::Command::Tasks::Superset < Quandl::Command::Task
|
|
14
14
|
superset download [code]
|
15
15
|
superset delete [code] }
|
16
16
|
|
17
|
+
def execute
|
18
|
+
# fire a subcommand if specified
|
19
|
+
return self.send(args.shift) if args.first.present? && self.respond_to?(args.first)
|
20
|
+
# otherwise default to upload
|
21
|
+
upload
|
22
|
+
end
|
23
|
+
|
17
24
|
def new
|
18
25
|
info Quandl::Client::Superset.example.to_qdf
|
19
26
|
end
|
data/quandl.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_runtime_dependency "commander", '4.1.5'
|
21
21
|
|
22
22
|
s.add_runtime_dependency "quandl_format", "0.4.2"
|
23
|
-
s.add_runtime_dependency "quandl_client", '2.7.
|
23
|
+
s.add_runtime_dependency "quandl_client", '2.7.7'
|
24
24
|
s.add_runtime_dependency "quandl_data", '1.4.1'
|
25
25
|
s.add_runtime_dependency "quandl_operation", '0.3.2'
|
26
26
|
s.add_runtime_dependency "quandl_babelfish", '0.0.9'
|
@@ -28,7 +28,9 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_runtime_dependency "json", '1.7.7'
|
29
29
|
s.add_runtime_dependency "minitar", '0.5.4'
|
30
30
|
s.add_runtime_dependency "thread", "0.1.3"
|
31
|
-
|
31
|
+
s.add_runtime_dependency "whedon", "0.0.2"
|
32
|
+
s.add_runtime_dependency "chronic", "0.10.2"
|
33
|
+
|
32
34
|
s.add_development_dependency "rake", "~> 10.1"
|
33
35
|
s.add_development_dependency "fog", "~> 1.19"
|
34
36
|
s.add_development_dependency "factory_girl", "~> 4.3"
|
@@ -37,5 +39,5 @@ Gem::Specification.new do |s|
|
|
37
39
|
s.add_development_dependency "pry", "~> 0.9"
|
38
40
|
s.add_development_dependency "guard", "~> 2.3"
|
39
41
|
s.add_development_dependency "guard-rspec", "~> 4.2"
|
40
|
-
s.add_development_dependency "quandl_utility"
|
42
|
+
s.add_development_dependency "quandl_utility", '0.1.1'
|
41
43
|
end
|
@@ -37,6 +37,7 @@ Source: "..\..\build\tarball\quandl-command\lib\*.*"; DestDir: "{app}\lib"; Flag
|
|
37
37
|
Source: "..\..\build\tarball\quandl-command\config\*.*"; DestDir: "{app}\config"; Flags: recursesubdirs;
|
38
38
|
Source: "..\..\build\tarball\quandl-command\vendor\*.*"; DestDir: "{app}\vendor"; Flags: recursesubdirs;
|
39
39
|
Source: "..\..\build\tarball\quandl\quandl.bat"; DestDir: "{app}\bin"; Flags: recursesubdirs;
|
40
|
+
Source: "..\..\VERSION"; DestDir: "{app}";
|
40
41
|
|
41
42
|
[Registry]
|
42
43
|
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: "expandsz"; ValueName: "QuandlPath"; \
|
@@ -1,53 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'open3'
|
4
|
+
require 'chronic'
|
4
5
|
|
5
|
-
describe "
|
6
|
+
describe "Quandl::Command::Tasks::Schedule" do
|
7
|
+
let(:schedule) { Quandl::Command::Tasks::Schedule.new(nil, nil)}
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
context "delete spec/fixtures/scraper.rb" do
|
11
|
-
its(:stdout){ should match 'Not Found' }
|
9
|
+
its "should parse 'at' time to cron correctly " do
|
10
|
+
schedule.stub_chain(:options, :at){'13:00'}
|
11
|
+
schedule.instance_eval{cron_at}.should == "0 13 * * *"
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# second upload
|
18
|
-
its(:stdout){ should match 'name: has already been taken' }
|
19
|
-
end
|
20
|
-
|
21
|
-
context "list" do
|
22
|
-
its(:stdout){ should match 'scraper.rb' }
|
23
|
-
end
|
24
|
-
|
25
|
-
context "show scraper.rb --output-format json" do
|
26
|
-
its(:stdout){ should match 'scraper_url' }
|
27
|
-
end
|
28
|
-
|
29
|
-
context "show scraper.rb -C 0" do
|
30
|
-
its(:stdout){ should eq "OK\n" }
|
31
|
-
end
|
32
|
-
|
33
|
-
context "show scraper.rb -C 1" do
|
34
|
-
its(:stdout){ should eq "scraper.rb\n" }
|
35
|
-
end
|
36
|
-
|
37
|
-
context "show scraper.rb -C 2" do
|
38
|
-
its(:stdout){ should eq "Scraper::Script\n" }
|
39
|
-
end
|
40
|
-
|
41
|
-
context "show scraper.rb --output-column 2" do
|
42
|
-
its(:stdout){ should eq "Scraper::Script\n" }
|
43
|
-
end
|
44
|
-
|
45
|
-
context "show scraper.rb --output-column 4" do
|
46
|
-
its(:stdout){ should match 's3.amazonaws' }
|
47
|
-
end
|
48
|
-
|
49
|
-
context "delete spec/fixtures/scraper.rb" do
|
50
|
-
its(:stdout){ should match 'OK' }
|
13
|
+
|
14
|
+
its "should parse 'at' time to cron correctly " do
|
15
|
+
schedule.stub_chain(:options, :at){'7pm monday'}
|
16
|
+
schedule.instance_eval{cron_at}.should == "0 19 * * 1"
|
51
17
|
end
|
52
|
-
|
53
18
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quandl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Hilscher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.7.
|
47
|
+
version: 2.7.7
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.7.
|
54
|
+
version: 2.7.7
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: quandl_data
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,34 @@ dependencies:
|
|
150
150
|
- - '='
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 0.1.3
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: whedon
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.0.2
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.0.2
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: chronic
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.10.2
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 0.10.2
|
153
181
|
- !ruby/object:Gem::Dependency
|
154
182
|
name: rake
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -266,16 +294,16 @@ dependencies:
|
|
266
294
|
name: quandl_utility
|
267
295
|
requirement: !ruby/object:Gem::Requirement
|
268
296
|
requirements:
|
269
|
-
- -
|
297
|
+
- - '='
|
270
298
|
- !ruby/object:Gem::Version
|
271
|
-
version:
|
299
|
+
version: 0.1.1
|
272
300
|
type: :development
|
273
301
|
prerelease: false
|
274
302
|
version_requirements: !ruby/object:Gem::Requirement
|
275
303
|
requirements:
|
276
|
-
- -
|
304
|
+
- - '='
|
277
305
|
- !ruby/object:Gem::Version
|
278
|
-
version:
|
306
|
+
version: 0.1.1
|
279
307
|
description: http://quandl.com/help/toolbelt
|
280
308
|
email:
|
281
309
|
- blake@hilscher.ca
|
@@ -307,6 +335,7 @@ files:
|
|
307
335
|
- lib/quandl/command/compatibility_check.rb
|
308
336
|
- lib/quandl/command/config.rb
|
309
337
|
- lib/quandl/command/presenter.rb
|
338
|
+
- lib/quandl/command/presenter/helper.rb
|
310
339
|
- lib/quandl/command/presenter/record.rb
|
311
340
|
- lib/quandl/command/presenters/dataset_presenter.rb
|
312
341
|
- lib/quandl/command/presenters/error_presenter.rb
|