quandl 0.3.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmI3MGNiMmJjYzNkNzU3ZWQzMjE3NTI0ZTlhNmZlMjMxMGNiMTk5NQ==
4
+ MDYxNjY3NjA1NTU3NmFiZGFiM2Q3YWU4YWNjZjM3NGRhZjJhZjIwOQ==
5
5
  data.tar.gz: !binary |-
6
- NzUwMGIyYjkxZGRkYTk5ZTc0ZTk3YTFjNzY5YzMzZDQ5OTY3ODNlYg==
6
+ MjdiZTc0M2UzOTczNjBiOTQxMDdkNTgwY2JmYWQ2OTAzYjc4YjFiNQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YmJjMTA3OGI1ODJhZWRjY2VkOWFkNzgxMTM4MTA5NmE0NzA1MDExZDFmNTBh
10
- MmUzNTgyMzM0OGIxYWY5MmJlNjk0ODIxZDhmYTNjMTRlYzE4NzA2NzAzNWIx
11
- NjU4ODMyOTgwZWYyYmU0OWQ4ZTg1ZWE3Y2NmZjk0YmFjZmM1NWQ=
9
+ ZDIwYTk5YWY2ZGZmYWY2MjBmMTNiNWI5ZjI2MTEwMzUwNmY2YzY3ZGEzMjYy
10
+ ZDhkNWJlMGRmZDA2MDJhZjA5NjNlN2I1NmIzNzg4MjE2MmEzMDI5MTMyZDEy
11
+ MzZmOGQyMWZjMjE4NmJjMDViZjBjNjAxNzg0ODFmZGIyMTQyMzI=
12
12
  data.tar.gz: !binary |-
13
- NWJiNzYyYWE5MmVkOGQxNGUwYjE5MTMzZGRiZTAxMzBlMTIxNmJkNDI4NGQz
14
- MjkxMjFkYzlmNzljNTJhZjlkOWQyMmVkN2JhMTE4YzdiZTYyNGRjOGRjOGM4
15
- ZTg0M2Q3YTM0MmQxY2U3ODE4NWYxYzNkN2MwY2RhM2ZkY2NhNTg=
13
+ MDg4MjRmYTY0NDI5NmRlYzA4OGQxNTMzMWVmNWFhMGQ4M2QzODU1YThjMmVi
14
+ ODYyMDBjNDViYjgwZDg2ZmEwZDUzNjViMWY1ZDZjZjk1ZDIyOTU3YjFlN2Nj
15
+ OWQ1MjZlMmE0NzE4NDgwNTI5NWQyN2JlMzRiZjA5MWQzZTE5ZGM=
data/UPGRADE.md CHANGED
@@ -1,4 +1,21 @@
1
- ## 0.3.0
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.0
1
+ 0.3.3
@@ -1,3 +1,4 @@
1
+ require 'quandl/command/presenter/helper'
1
2
  require 'quandl/command/presenter/record'
2
3
 
3
4
  require 'quandl/command/presenters/dataset_presenter'
@@ -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 repsonse errors
99
- re = messages.delete(:response_errors) if messages.is_a?(Hash) && messages.has_key?(:response_errors)
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 to be run daily.
21
+ You have successfully scheduled scraper.rb.
21
22
 
22
- $ quandl schedule add scraper.rb --name weekly_scraper.rb --frequency weekly
23
- You have successfully scheduled weekly-scraper.rb to be run weekly.
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 replace scraper.rb}
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
- frequency: "How often the scraper should be run. [ daily, weekly, monthly, quaterly, annually ]",
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
- present(scrapers)
39
+ scrapers.each { |x| script_info x}
37
40
  end
38
41
 
39
42
  def show
40
- present(scraper)
43
+ script_info scraper
41
44
  end
42
45
 
43
46
  def add
44
- Quandl::Client::Scraper.create( name: name, scraper: args.first )
45
- info("'#{scraper.name}' was added.")
46
- info("#{schedule_message}")
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
- info("'#{scraper.name}' was deleted")
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.destroy if scraper.respond_to?(:destroy)
74
- Quandl::Client::Scraper.create( name: name, scraper: args.first )
75
- info("'#{scraper.name}' was replaced.")
76
- info("#{schedule_message}")
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
- "It will run 3 times a day starting immediately. Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
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
@@ -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.4'
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 "./bin/quandl schedule" do
6
+ describe "Quandl::Command::Tasks::Schedule" do
7
+ let(:schedule) { Quandl::Command::Tasks::Schedule.new(nil, nil)}
6
8
 
7
- let(:command){ self.class.superclass.description }
8
- subject{ quandl("schedule #{command}") }
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
- context "add spec/fixtures/scraper.rb" do
15
- # first upload
16
- its(:stdout){ should match 'Created' }
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.0
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-15 00:00:00.000000000 Z
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.4
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.4
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: '0'
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: '0'
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