quandl 0.2.27 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +70 -17
  3. data/Rakefile +7 -86
  4. data/UPGRADE.md +23 -0
  5. data/VERSION +1 -0
  6. data/lib/quandl/command.rb +11 -3
  7. data/lib/quandl/command/config.rb +88 -0
  8. data/lib/quandl/command/presenter.rb +74 -0
  9. data/lib/quandl/command/presenter/record.rb +121 -0
  10. data/lib/quandl/command/presenters/dataset_presenter.rb +19 -0
  11. data/lib/quandl/command/presenters/error_presenter.rb +31 -0
  12. data/lib/quandl/command/presenters/nil_class_presenter.rb +10 -0
  13. data/lib/quandl/command/presenters/scraper_presenter.rb +25 -0
  14. data/lib/quandl/command/presenters/superset_presenter.rb +10 -0
  15. data/lib/quandl/command/task.rb +40 -0
  16. data/lib/quandl/command/task/callbacks.rb +47 -0
  17. data/lib/quandl/command/task/clientable.rb +65 -0
  18. data/lib/quandl/command/task/commandable.rb +104 -0
  19. data/lib/quandl/command/task/configurable.rb +79 -0
  20. data/lib/quandl/command/task/inputable.rb +37 -0
  21. data/lib/quandl/command/task/logging.rb +83 -0
  22. data/lib/quandl/command/task/presentation.rb +37 -0
  23. data/lib/quandl/command/task/reportable.rb +35 -0
  24. data/lib/quandl/command/task/threading.rb +117 -0
  25. data/lib/quandl/command/task/translations.rb +37 -0
  26. data/lib/quandl/command/task/updatable.rb +77 -0
  27. data/lib/quandl/command/tasks.rb +6 -5
  28. data/lib/quandl/command/tasks/delete.rb +10 -67
  29. data/lib/quandl/command/tasks/download.rb +11 -78
  30. data/lib/quandl/command/tasks/info.rb +2 -2
  31. data/lib/quandl/command/tasks/list.rb +12 -24
  32. data/lib/quandl/command/tasks/login.rb +4 -4
  33. data/lib/quandl/command/tasks/replace.rb +58 -0
  34. data/lib/quandl/command/tasks/schedule.rb +106 -0
  35. data/lib/quandl/command/tasks/search.rb +39 -0
  36. data/lib/quandl/command/tasks/superset.rb +59 -0
  37. data/lib/quandl/command/tasks/uninstall.rb +1 -1
  38. data/lib/quandl/command/tasks/update.rb +2 -2
  39. data/lib/quandl/command/tasks/upload.rb +13 -26
  40. data/lib/quandl/command/version.rb +1 -1
  41. data/quandl.gemspec +5 -3
  42. data/spec/fixtures/scraper.rb +6 -0
  43. data/spec/lib/quandl/command/delete_spec.rb +19 -11
  44. data/spec/lib/quandl/command/download_spec.rb +11 -4
  45. data/spec/lib/quandl/command/replace_spec.rb +23 -0
  46. data/spec/lib/quandl/command/schedule_spec.rb +53 -0
  47. data/spec/lib/quandl/command/superset_spec.rb +28 -0
  48. data/spec/lib/quandl/command/upload_spec.rb +71 -24
  49. data/spec/lib/quandl/command_spec.rb +1 -9
  50. data/spec/spec_helper.rb +36 -1
  51. data/tasks/toolbelt/build/tarball.rb +2 -2
  52. metadata +55 -10
  53. data/lib/quandl/command/qconfig.rb +0 -86
  54. data/lib/quandl/command/tasks/base.rb +0 -314
@@ -0,0 +1,74 @@
1
+ require 'quandl/command/presenter/record'
2
+
3
+ require 'quandl/command/presenters/dataset_presenter'
4
+ require 'quandl/command/presenters/nil_class_presenter'
5
+ require 'quandl/command/presenters/error_presenter'
6
+ require 'quandl/command/presenters/scraper_presenter'
7
+ require 'quandl/command/presenters/superset_presenter'
8
+
9
+ module Quandl
10
+ module Command
11
+ class Presenter
12
+
13
+ class << self
14
+
15
+ def wrap_record_in_presenter(record, options)
16
+ klass = find_presenter_for_record(record, options)
17
+ klass.new(record, options)
18
+ end
19
+
20
+ def find_presenter_for_record(record, options={})
21
+ name = 'Error' if record.kind_of?(Exception)
22
+ name = options[:as] || record.class.name.to_s.split("::").last unless name.present?
23
+ "Quandl::Command::Presenters::#{name}Presenter".constantize rescue Quandl::Command::Presenter::Record
24
+ end
25
+
26
+ end
27
+
28
+ attr_accessor :options, :type
29
+
30
+ def initialize( object, opts={} )
31
+ self.type = ( object.try(:class) == Her::Collection ) ? :docs : :doc
32
+ self.options = { type: type }.merge( opts.symbolize_keys! )
33
+ self.collection = object
34
+ end
35
+
36
+ def each(&block)
37
+ collection.each do |presenter|
38
+ block.call( presenter )
39
+ end
40
+ end
41
+
42
+ def each_to_format(type, &block)
43
+ collection.each do |record|
44
+ output = record.send("to_#{type}") if record.respond_to?("to_#{type}")
45
+ block.call( output, record.object )
46
+ end
47
+ end
48
+
49
+ def to_format(type)
50
+ output = []
51
+ collection.each do |record|
52
+ output << record.send("to_#{type}") if record.respond_to?("to_#{type}")
53
+ end
54
+ output.join("\n")
55
+ end
56
+
57
+ def collection=(records)
58
+ @collection = []
59
+ records = Array(records).flatten
60
+ records.each do |record|
61
+ @collection << self.class.wrap_record_in_presenter(record, options)
62
+ end
63
+ # present nil if the collection is empty
64
+ @collection = [self.class.wrap_record_in_presenter( nil, options )] if @collection.blank?
65
+ @collection
66
+ end
67
+
68
+ def collection
69
+ @collection ||= []
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,121 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenter
4
+
5
+ class Record
6
+
7
+ attr_accessor :object, :options
8
+
9
+ def initialize(*args)
10
+ self.options = args.extract_options!
11
+ self.object = args.first
12
+ end
13
+
14
+ # supported formats
15
+
16
+ def to_format(f)
17
+ self.send("to_#{f}") if self.respond_to?("to_#{f}")
18
+ end
19
+
20
+
21
+ def to_pipes
22
+ column = options[:output_column] if options.present? && options.is_a?(Hash)
23
+ pipes = as_pipes.dup.compact
24
+ pipes = [ pipes[ column.to_i ] ] if column.present? && column.to_s.numeric?
25
+ pipes.join(" | ")
26
+ end
27
+
28
+ def to_stderr
29
+ as_stderr
30
+ end
31
+
32
+ def as_stderr
33
+ output = ''
34
+ output += "#{id}\n" if id.present?
35
+ output += "#{detail}\n" if detail.present?
36
+ output += errors if errors.present?
37
+ output += object.to_s if object.kind_of?(Exception)
38
+ output += object.backtrace.join("\n") if object.respond_to?(:backtrace) && options[:trace] == true
39
+ output += "\n---\n"
40
+ end
41
+
42
+ def to_qdf
43
+ object.try(:to_qdf)
44
+ end
45
+
46
+ def to_csv
47
+ object.try(:to_csv)
48
+ end
49
+
50
+ def to_json
51
+ as_json.try(:to_json)
52
+ end
53
+
54
+ def as_pipes
55
+ [ status, id, detail, message ]
56
+ end
57
+
58
+ def as_json
59
+ json = { status: status, id: id, detail: detail, message: message }
60
+ json[:attributes] = object.attributes if object.respond_to?(:attributes)
61
+ json[:metadata] = object.metadata if object.respond_to?(:metadata)
62
+ json[:errors] = object.error_messages if object.respond_to?(:error_messages)
63
+ json
64
+ end
65
+
66
+ # default attribute mappings
67
+
68
+ def valid?
69
+ return true if object.nil?
70
+ return true if [200,201,404].include?(object.try(:status))
71
+ false
72
+ end
73
+
74
+ def status
75
+ return Quandl::Client::HTTP_STATUS_CODES[422] if object.try(:errors).try(:present?)
76
+ return object.try(:human_status) if object.respond_to?(:human_status) && object.human_status.present?
77
+ Quandl::Client::HTTP_STATUS_CODES[404]
78
+ end
79
+
80
+ def id
81
+ object.try(:id)
82
+ end
83
+
84
+ def message
85
+ errors_without_spaces
86
+ end
87
+
88
+ def detail
89
+ end
90
+
91
+ def errors_without_spaces
92
+ errors.to_s.gsub("\n", ' ')
93
+ end
94
+
95
+ def errors
96
+ result = []
97
+ 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(", ")
107
+ end
108
+
109
+ def docs?
110
+ options[:type] == :docs
111
+ end
112
+
113
+ def doc?
114
+ options[:type] == :doc
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,19 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenters
4
+
5
+ class DatasetPresenter < Quandl::Command::Presenter::Record
6
+
7
+ def id
8
+ object.try(:full_code)
9
+ end
10
+
11
+ def detail
12
+ object.try(:full_url)
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenters
4
+
5
+ class ErrorPresenter < Quandl::Command::Presenter::Record
6
+
7
+ def as_pipes
8
+ [ status, id, detail, message.gsub(/\n+/, '. ') ]
9
+ end
10
+
11
+ def status
12
+ Quandl::Client::HTTP_STATUS_CODES[422]
13
+ end
14
+
15
+ def id
16
+ 'Error'
17
+ end
18
+
19
+ def detail
20
+ object.class.to_s
21
+ end
22
+
23
+ def message
24
+ object.to_s
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenters
4
+
5
+ class NilClassPresenter < Quandl::Command::Presenter::Record
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenters
4
+
5
+ class ScraperPresenter < Quandl::Command::Presenter::Record
6
+
7
+ def as_pipes
8
+ pipes = [object.name]
9
+ #pipes += [object.scraper_url, object.git_url, object.git_reference].compact if doc?
10
+ pipes
11
+ end
12
+
13
+ def id
14
+ object.try(:name)
15
+ end
16
+
17
+ def detail
18
+ object.try(:type)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ module Quandl
2
+ module Command
3
+ class Presenters
4
+
5
+ class SupersetPresenter < DatasetPresenter
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ require 'active_model'
2
+ require 'quandl/pattern'
3
+ require 'quandl/pattern/client'
4
+ require 'quandl/operation'
5
+
6
+ require 'quandl/command/task/configurable'
7
+ require 'quandl/command/task/callbacks'
8
+ require 'quandl/command/task/reportable'
9
+ require 'quandl/command/task/commandable'
10
+ require 'quandl/command/task/logging'
11
+ require 'quandl/command/task/presentation'
12
+ require 'quandl/command/task/threading'
13
+ require 'quandl/command/task/translations'
14
+ require 'quandl/command/task/updatable'
15
+ require 'quandl/command/task/clientable'
16
+ require 'quandl/command/task/inputable'
17
+
18
+ module Quandl
19
+ module Command
20
+
21
+ class Task
22
+
23
+ include ActiveModel::Validations
24
+
25
+ include Quandl::Command::Task::Configurable
26
+ include Quandl::Command::Task::Callbacks
27
+ include Quandl::Command::Task::Commandable
28
+ include Quandl::Command::Task::Logging
29
+ include Quandl::Command::Task::Presentation
30
+ include Quandl::Command::Task::Threading
31
+ include Quandl::Command::Task::Translations
32
+ include Quandl::Command::Task::Updatable
33
+ include Quandl::Command::Task::Clientable
34
+ include Quandl::Command::Task::Reportable
35
+ include Quandl::Command::Task::Inputable
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ module Quandl
2
+ module Command
3
+ class Task
4
+
5
+ module Callbacks
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+
11
+ extend ActiveModel::Callbacks
12
+ define_model_callbacks :execute
13
+
14
+ before_execute :run_task_validations!
15
+
16
+ end
17
+
18
+ module ClassMethods
19
+
20
+ def disable_in_gem!
21
+ before_execute :disable_in_gem!
22
+ end
23
+
24
+ end
25
+
26
+ def run_task_validations!
27
+ unless valid?
28
+ error( table(errors.full_messages) )
29
+ false
30
+ end
31
+ end
32
+
33
+ def disable_in_gem!
34
+ if force_yes?
35
+ info("You have forced update!")
36
+ true
37
+ elsif Dir.exists?( File.join( Tasks.root, ".git") ) || File.exists?( File.join( Tasks.root, "Gemfile") )
38
+ fatal("#{self.class.command_name} is only permitted when installed as a package! http://quandl.com/help/toolbelt")
39
+ false
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,65 @@
1
+ module Quandl
2
+ module Command
3
+ class Task
4
+
5
+ module Clientable
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def authenticated_users_only!
15
+ before_execute :authenticated_users_only!
16
+ end
17
+
18
+ def warn_unauthenticated_users
19
+ before_execute :warn_unauthenticated_users
20
+ end
21
+
22
+ def autoload_quandl_client
23
+ before_execute :autoload_quandl_client
24
+ end
25
+
26
+ end
27
+
28
+ def current_user
29
+ @current_user ||= Quandl::Client::User.info
30
+ end
31
+
32
+ protected
33
+
34
+ def clear_session!
35
+ @auth_token = nil
36
+ @current_user = nil
37
+ autoload_quandl_client
38
+ end
39
+
40
+ def authenticated_users_only!
41
+ if auth_token.blank?
42
+ fatal("You must authenticate to use #{self.class.command_name}! 'quandl login' OR --token xyz923")
43
+ false
44
+ end
45
+ end
46
+
47
+ def warn_unauthenticated_users
48
+ error("WARN: Authenticate your requests! 'quandl login' OR --token xyz923") if auth_token.blank?
49
+ end
50
+
51
+ def autoload_quandl_client
52
+ require 'thread/pool'
53
+ require 'quandl/format'
54
+ require 'quandl/command/client_ext'
55
+ Quandl::Client.use( quandl_url )
56
+ Quandl::Client.token = auth_token
57
+ Quandl::Client.request_source = 'quandl_command'
58
+ Quandl::Client.request_version = Quandl::Command::VERSION
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+ end