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 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