quandl_client 2.7.5 → 2.7.6

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.
Files changed (56) hide show
  1. data/.gitignore +7 -7
  2. data/.rspec +1 -1
  3. data/.travis.yml +20 -20
  4. data/.yardopts +2 -2
  5. data/Gemfile +12 -12
  6. data/Guardfile +8 -8
  7. data/LICENSE +7 -7
  8. data/README.md +303 -303
  9. data/Rakefile +31 -35
  10. data/UPGRADE.md +190 -213
  11. data/VERSION +1 -1
  12. data/examples/create.rb +32 -32
  13. data/examples/find.rb +17 -17
  14. data/examples/login.rb +12 -12
  15. data/examples/search.rb +12 -12
  16. data/examples/trims.rb +15 -15
  17. data/lib/quandl/client.rb +49 -49
  18. data/lib/quandl/client/base.rb +91 -91
  19. data/lib/quandl/client/base/attributes.rb +15 -15
  20. data/lib/quandl/client/base/model.rb +40 -40
  21. data/lib/quandl/client/base/search.rb +74 -74
  22. data/lib/quandl/client/base/validation.rb +101 -101
  23. data/lib/quandl/client/middleware.rb +9 -9
  24. data/lib/quandl/client/middleware/parse_json.rb +85 -85
  25. data/lib/quandl/client/models/dataset.rb +261 -245
  26. data/lib/quandl/client/models/dataset/data.rb +57 -57
  27. data/lib/quandl/client/models/location.rb +10 -10
  28. data/lib/quandl/client/models/report.rb +14 -14
  29. data/lib/quandl/client/models/scraper.rb +16 -16
  30. data/lib/quandl/client/models/sheet.rb +50 -50
  31. data/lib/quandl/client/models/source.rb +48 -40
  32. data/lib/quandl/client/models/superset.rb +59 -59
  33. data/lib/quandl/client/models/user.rb +7 -7
  34. data/lib/quandl/client/version.rb +14 -14
  35. data/lib/quandl/her/remove_method_data.rb +8 -8
  36. data/lib/quandl/pattern.rb +37 -37
  37. data/lib/quandl/pattern/client.rb +8 -8
  38. data/quandl_client.gemspec +33 -33
  39. data/spec/factories/dataset.rb +10 -10
  40. data/spec/factories/sheet.rb +7 -7
  41. data/spec/factories/source.rb +9 -9
  42. data/spec/fixtures/scraper.rb +5 -5
  43. data/spec/lib/quandl/client/dataset/attributes_spec.rb +63 -63
  44. data/spec/lib/quandl/client/dataset/data_spec.rb +92 -92
  45. data/spec/lib/quandl/client/dataset/location_spec.rb +65 -65
  46. data/spec/lib/quandl/client/dataset/persistence_spec.rb +104 -104
  47. data/spec/lib/quandl/client/dataset/search_spec.rb +19 -19
  48. data/spec/lib/quandl/client/dataset/source_spec.rb +47 -47
  49. data/spec/lib/quandl/client/dataset/trim_spec.rb +35 -35
  50. data/spec/lib/quandl/client/dataset/validation_spec.rb +68 -68
  51. data/spec/lib/quandl/client/dataset_spec.rb +57 -57
  52. data/spec/lib/quandl/client/scraper_spec.rb +71 -71
  53. data/spec/lib/quandl/client/sheet_spec.rb +37 -37
  54. data/spec/lib/quandl/client/source_spec.rb +51 -51
  55. data/spec/spec_helper.rb +30 -30
  56. metadata +27 -5
@@ -1,10 +1,10 @@
1
- require 'faraday'
2
- require 'quandl/client/middleware/parse_json'
3
-
4
- module Quandl
5
- module Client
6
- module Middleware
7
-
8
- end
9
- end
1
+ require 'faraday'
2
+ require 'quandl/client/middleware/parse_json'
3
+
4
+ module Quandl
5
+ module Client
6
+ module Middleware
7
+
8
+ end
9
+ end
10
10
  end
@@ -1,86 +1,86 @@
1
- require 'json'
2
-
3
- module Quandl
4
- module Client
5
- module Middleware
6
-
7
- class ParseJSON < Faraday::Response::Middleware
8
-
9
- def on_complete(env)
10
- env[:body] = case env[:status]
11
- when 204
12
- parse('{}', env)
13
- else
14
- parse(env[:body], env)
15
- end
16
- end
17
-
18
- def parse(body, env)
19
- json = parse_json(body, env)
20
- json.has_key?(:docs) ? format_collection( json, env ) : format_record( json, env )
21
- end
22
-
23
- def format_record(json, env)
24
- errors = json.delete(:errors) || {}
25
- metadata = json.delete(:metadata) || {}
26
- # collect some response data
27
- metadata.merge!({
28
- status: env[:status],
29
- headers: env[:response_headers],
30
- })
31
- # return object
32
- object = {
33
- :data => json,
34
- :errors => errors,
35
- :metadata => metadata
36
- }
37
- env[:status] = 200
38
- object
39
- end
40
-
41
- def format_collection(json, env)
42
- errors = json.delete(:errors) || {}
43
- metadata = json.delete(:metadata) || {}
44
- docs = json.delete(:docs)
45
- # collect some response data
46
- metadata.merge!(json).merge!({
47
- status: env[:status],
48
- headers: env[:response_headers],
49
- })
50
- # each doc metadata references metadata
51
- docs.each{|d| d[:metadata] = metadata }
52
- # return object
53
- object = {
54
- :data => docs,
55
- :errors => errors,
56
- :metadata => metadata
57
- }
58
- env[:status] = 200
59
- object
60
- end
61
-
62
- def parse_json(body = nil, env)
63
- body ||= '{}'
64
- json = begin
65
- JSON.parse(body).symbolize_keys!
66
- rescue JSON::ParserError
67
- nil
68
- end
69
- # invalid json body?
70
- if json.blank?
71
- # fallback to error message
72
- json = {
73
- id: 1,
74
- errors: {
75
- parse_errors: [ "Quandl::Client::ParseJSON error. status: #{env[:status]}, body: #{body.inspect}" ]
76
- }
77
- }
78
- end
79
- json
80
- end
81
-
82
- end
83
-
84
- end
85
- end
1
+ require 'json'
2
+
3
+ module Quandl
4
+ module Client
5
+ module Middleware
6
+
7
+ class ParseJSON < Faraday::Response::Middleware
8
+
9
+ def on_complete(env)
10
+ env[:body] = case env[:status]
11
+ when 204
12
+ parse('{}', env)
13
+ else
14
+ parse(env[:body], env)
15
+ end
16
+ end
17
+
18
+ def parse(body, env)
19
+ json = parse_json(body, env)
20
+ json.has_key?(:docs) ? format_collection( json, env ) : format_record( json, env )
21
+ end
22
+
23
+ def format_record(json, env)
24
+ errors = json.delete(:errors) || {}
25
+ metadata = json.delete(:metadata) || {}
26
+ # collect some response data
27
+ metadata.merge!({
28
+ status: env[:status],
29
+ headers: env[:response_headers],
30
+ })
31
+ # return object
32
+ object = {
33
+ :data => json,
34
+ :errors => errors,
35
+ :metadata => metadata
36
+ }
37
+ env[:status] = 200
38
+ object
39
+ end
40
+
41
+ def format_collection(json, env)
42
+ errors = json.delete(:errors) || {}
43
+ metadata = json.delete(:metadata) || {}
44
+ docs = json.delete(:docs)
45
+ # collect some response data
46
+ metadata.merge!(json).merge!({
47
+ status: env[:status],
48
+ headers: env[:response_headers],
49
+ })
50
+ # each doc metadata references metadata
51
+ docs.each{|d| d[:metadata] = metadata }
52
+ # return object
53
+ object = {
54
+ :data => docs,
55
+ :errors => errors,
56
+ :metadata => metadata
57
+ }
58
+ env[:status] = 200
59
+ object
60
+ end
61
+
62
+ def parse_json(body = nil, env)
63
+ body ||= '{}'
64
+ json = begin
65
+ JSON.parse(body).symbolize_keys!
66
+ rescue JSON::ParserError
67
+ nil
68
+ end
69
+ # invalid json body?
70
+ if json.blank?
71
+ # fallback to error message
72
+ json = {
73
+ id: 1,
74
+ errors: {
75
+ parse_errors: [ "Quandl::Client::ParseJSON error. status: #{env[:status]}, body: #{body.inspect}" ]
76
+ }
77
+ }
78
+ end
79
+ json
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
86
86
  end
@@ -1,246 +1,262 @@
1
- class Quandl::Client::Dataset < Quandl::Client::Base
2
-
3
- require 'quandl/client/models/dataset/data'
4
-
5
- ##########
6
- # SCOPES #
7
- ##########
8
- class << self
9
- def touch_existing(id)
10
- put(File.join(Quandl::Client::Base.url_with_version, "datasets/#{id}/touch")).exists?
11
- end
12
-
13
- def find(value)
14
- # preformat
15
- value = format_id(value)
16
- # short-circuit if value is illegal
17
- return nil unless value.is_a?(Integer) || value.to_s =~ %r{^#{Quandl::Pattern.full_code}$}
18
- # search
19
- super(value)
20
- end
21
-
22
- def format_id(value)
23
- # enforce code formatting
24
- if value.is_a?(String)
25
- # strip extra whitespace
26
- value = value.strip.rstrip
27
- # ensure slashes are forward facing
28
- value = value.gsub("\\","/").gsub(".","/")
29
- # ensure uppercase
30
- value = value.upcase
31
- end
32
- value
33
- end
34
-
35
- end
36
-
37
- # SEARCH
38
- scope :query, :rows, :owner
39
- scope :page, ->(p){ where( page: p.to_i )}
40
- scope :source_code, ->(c){ where( code: c.to_s.upcase )}
41
-
42
- ###############
43
- # ASSOCIATIONS #
44
- ###############
45
-
46
- def source
47
- @source ||= Quandl::Client::Source.find(self.source_code)
48
- end
49
-
50
- ###############
51
- # VALIDATIONS #
52
- ###############
53
-
54
- validates :code, presence: true, format: { with: Quandl::Pattern.code, message: "is invalid. Expected format: #{Quandl::Pattern.code.to_example}" }
55
- validates :display_url, allow_blank: true, url: true
56
- validate :data_should_be_valid!
57
- validate :dataset_data_should_be_valid!
58
- validate :data_row_count_should_match_column_count!
59
- validate :data_columns_should_not_exceed_column_names!
60
- validate :data_rows_should_have_equal_columns!
61
- validate :ambiguous_code_requires_source_code!
62
-
63
-
64
- ##############
65
- # PROPERTIES #
66
- ##############
67
-
68
- attributes :source_code, :code, :name, :urlize_name,
69
- :description, :updated_at, :frequency,
70
- :from_date, :to_date, :column_names, :private, :type,
71
- :display_url, :column_spec, :import_spec, :import_url,
72
- :locations_attributes, :availability_delay, :refreshed_at
73
-
74
- before_save :enforce_required_formats
75
-
76
- after_save :save_dataset_data
77
-
78
- alias_method :locations, :locations_attributes
79
- alias_method :locations=, :locations_attributes=
80
-
81
- def reference_url
82
- self.display_url
83
- end
84
- def reference_url=(value)
85
- value = "http://#{value}" if value.present? && !(value =~ /:\/\//)
86
- self.display_url = value
87
- end
88
-
89
- def full_url
90
- File.join(Quandl::Client::Base.url.gsub(/api\/?/, ''), full_code)
91
- end
92
-
93
- def full_code
94
- File.join(self.source_code.to_s, self.code.to_s)
95
- end
96
-
97
- # DATA
98
-
99
- def data
100
- defined?(@data) ? @data : data_scope
101
- end
102
-
103
- def data=(value)
104
- @data = Quandl::Data.new(value).sort_descending
105
- end
106
-
107
- def data?
108
- @data.is_a?(Quandl::Data)
109
- end
110
-
111
- def delete_data
112
- # cant delete unsaved records
113
- return false if new_record?
114
- # delete and return success / failure
115
- self.class.destroy_existing("#{id}/data").saved?
116
- end
117
-
118
- def delete_rows(*dates)
119
- # cant delete unsaved records
120
- return false if new_record?
121
- # collect dates
122
- query = { dates: Array(dates).flatten }.to_query
123
- # delete and return success / failure
124
- self.class.destroy_existing("#{id}/data/rows?#{query}").saved?
125
- end
126
-
127
- def data_scope
128
- @data_scope ||= Quandl::Client::Dataset::Data.with_id(id)
129
- end
130
-
131
- def dataset_data
132
- @dataset_data ||= Quandl::Client::Dataset::Data.new( id: id )
133
- end
134
-
135
- def dataset_data?
136
- @dataset_data.is_a?(Quandl::Client::Dataset::Data)
137
- end
138
-
139
- def reload
140
- @dataset_data = nil
141
- @data_scope = nil
142
- @full_code = nil
143
- end
144
-
145
- protected
146
-
147
- def data_should_be_valid!
148
- if data? && !data.valid?
149
- data.errors.each{|k,v| self.errors.add( k,v ) }
150
- return false
151
- end
152
- true
153
- end
154
-
155
- def dataset_data_should_be_valid!
156
- if dataset_data? && !dataset_data.valid?
157
- dataset_data.errors.each{|k,v| self.errors.add( k,v ) }
158
- return false
159
- end
160
- true
161
- end
162
-
163
- def ambiguous_code_requires_source_code!
164
- if code.to_s.numeric? && source_code.blank?
165
- message = %Q{Pure numerical codes like "#{code}" are not allowed unless you include a source code. Do this:\nsource_code: <USERNAME>\ncode: #{code}}
166
- self.errors.add( :data, message )
167
- return false
168
- end
169
- true
170
- end
171
-
172
- def data_columns_should_not_exceed_column_names!
173
- if errors.size == 0 && data? && data.present? && column_names.present? && data.first.count != column_names.count
174
- self.errors.add( :data, "You may not change the number of columns in a dataset. This dataset has #{column_names.count} columns but you tried to send #{data.first.count} columns." )
175
- return false
176
- end
177
- true
178
- end
179
-
180
- def data_rows_should_have_equal_columns!
181
- # skip validation unless data is present
182
- return true unless data? && data.present?
183
- # use first row as expected column count
184
- column_count = data[0].count
185
- # check each row
186
- data.each_with_index do |row, index|
187
- # the row is valid if it's count matches the first row's count
188
- next if row.count == column_count
189
- # the row is invalid if the count is mismatched
190
- self.errors.add( :data, "Unexpected number of points in this row:\n#{row.join(',')}\nFound #{row.size-1} but expected #{data[0].size-1} based on precedent from the first row (#{data[0].join(',')})" )
191
- # return validation failure
192
- return false
193
- end
194
- true
195
- end
196
-
197
- def data_row_count_should_match_column_count!
198
- # skip validation unless data and column_names present
199
- return true unless data? && data.present? && column_names.present?
200
- # count the number of expected columns
201
- column_count = column_names.count
202
- # check each row
203
- data.each_with_index do |row, index|
204
- # the row is valid if it's count matches the first row's count
205
- next if row.count == column_count
206
- # the row is invalid if the count is mismatched
207
- self.errors.add( :data, "Unexpected number of points in this row:\n#{row.join(',')}\nFound #{row.size-1} but expected #{column_names.count-1} based on precedent from the header row (#{column_names.join(',')})" )
208
- # return validation failure
209
- return false
210
- end
211
- true
212
- end
213
-
214
- def save_dataset_data
215
- return if (!saved? && id.blank?)
216
- return if !data? || data.blank?
217
-
218
- dataset_data.id = id
219
- dataset_data.data = data.to_csv
220
- dataset_data.save
221
- # update dataset's attributes with dataset_data's attributes
222
- attributes.each{|k,v| attributes[k] = dataset_data.attributes[k] if dataset_data.attributes.has_key?(k) }
223
- # update dataset errors with dataset_data
224
- @metadata[:status] = dataset_data.status unless dataset_data.saved?
225
- # inherit_errors(dataset_data) unless dataset_data.saved?
226
- end
227
-
228
- def inherit_errors(object)
229
- return unless object.respond_to?(:response_errors) && object.response_errors.respond_to?(:each)
230
- object.response_errors.each do |key, messages|
231
- if messages.respond_to?(:each)
232
- messages.each{|message| errors.add(key, message) }
233
- end
234
- end
235
- @metadata[:status] = object.status
236
- object
237
- end
238
-
239
- def enforce_required_formats
240
- # self.data = Quandl::Data.new(data).to_csv
241
- self.source_code = self.source_code.to_s.upcase
242
- self.code = self.code.to_s.upcase
243
- self.locations_attributes = locations_attributes.to_json if locations_attributes.respond_to?(:to_json) && !locations_attributes.kind_of?(String)
244
- end
245
-
1
+ class Quandl::Client::Dataset < Quandl::Client::Base
2
+
3
+ require 'quandl/client/models/dataset/data'
4
+
5
+ ##########
6
+ # SCOPES #
7
+ ##########
8
+ class << self
9
+ def touch_existing(id)
10
+ put(File.join(Quandl::Client::Base.url_with_version, "datasets/#{id}/touch")).exists?
11
+ end
12
+
13
+ def find(value)
14
+ # preformat
15
+ value = format_id(value)
16
+ # short-circuit if value is illegal
17
+ return nil unless value.is_a?(Integer) || value.to_s =~ %r{^#{Quandl::Pattern.full_code}$}
18
+ # search
19
+ super(value)
20
+ end
21
+
22
+ def format_id(value)
23
+ # enforce code formatting
24
+ if value.is_a?(String)
25
+ # strip extra whitespace
26
+ value = value.strip.rstrip
27
+ # ensure slashes are forward facing
28
+ value = value.gsub("\\","/").gsub(".","/")
29
+ # ensure uppercase
30
+ value = value.upcase
31
+ end
32
+ value
33
+ end
34
+
35
+ end
36
+
37
+ # SEARCH
38
+ scope :query, :rows, :owner
39
+ scope :page, ->(p){ where( page: p.to_i )}
40
+ scope :source_code, ->(c){ where( code: c.to_s.upcase )}
41
+
42
+ ###############
43
+ # ASSOCIATIONS #
44
+ ###############
45
+
46
+ def source
47
+ @source ||= Quandl::Client::Source.find(self.source_code)
48
+ end
49
+
50
+ ###############
51
+ # VALIDATIONS #
52
+ ###############
53
+
54
+ validates :code, presence: true, format: { with: Quandl::Pattern.code, message: "is invalid. Expected format: #{Quandl::Pattern.code.to_example}" }
55
+ validates :display_url, allow_blank: true, url: true
56
+ validate :data_should_be_valid!
57
+ validate :dataset_data_should_be_valid!
58
+ validate :data_row_count_should_match_column_count!
59
+ validate :data_columns_should_not_exceed_column_names!
60
+ validate :data_rows_should_have_equal_columns!
61
+ validate :ambiguous_code_requires_source_code!
62
+
63
+ validate :source_code_should_exist!
64
+
65
+
66
+ ##############
67
+ # PROPERTIES #
68
+ ##############
69
+
70
+ attributes :source_code, :code, :name, :urlize_name,
71
+ :description, :updated_at, :frequency,
72
+ :from_date, :to_date, :column_names, :private, :type,
73
+ :display_url, :column_spec, :import_spec, :import_url,
74
+ :locations_attributes, :availability_delay, :refreshed_at
75
+
76
+ before_save :enforce_required_formats
77
+
78
+ after_save :save_dataset_data
79
+
80
+ alias_method :locations, :locations_attributes
81
+ alias_method :locations=, :locations_attributes=
82
+
83
+ def reference_url
84
+ self.display_url
85
+ end
86
+ def reference_url=(value)
87
+ value = "http://#{value}" if value.present? && !(value =~ /:\/\//)
88
+ self.display_url = value
89
+ end
90
+
91
+ def full_url
92
+ File.join(Quandl::Client::Base.url.gsub(/api\/?/, ''), full_code)
93
+ end
94
+
95
+ def full_code
96
+ File.join(self.source_code.to_s, self.code.to_s)
97
+ end
98
+
99
+ # DATA
100
+
101
+ def data
102
+ defined?(@data) ? @data : data_scope
103
+ end
104
+
105
+ def data=(value)
106
+ @data = Quandl::Data.new(value).sort_descending
107
+ end
108
+
109
+ def data?
110
+ @data.is_a?(Quandl::Data)
111
+ end
112
+
113
+ def source_code=(v)
114
+ write_attribute(:source_code, v.to_s.upcase)
115
+ end
116
+
117
+ def delete_data
118
+ # cant delete unsaved records
119
+ return false if new_record?
120
+ # delete and return success / failure
121
+ self.class.destroy_existing("#{id}/data").saved?
122
+ end
123
+
124
+ def delete_rows(*dates)
125
+ # cant delete unsaved records
126
+ return false if new_record?
127
+ # collect dates
128
+ query = { dates: Array(dates).flatten }.to_query
129
+ # delete and return success / failure
130
+ self.class.destroy_existing("#{id}/data/rows?#{query}").saved?
131
+ end
132
+
133
+ def data_scope
134
+ @data_scope ||= Quandl::Client::Dataset::Data.with_id(id)
135
+ end
136
+
137
+ def dataset_data
138
+ @dataset_data ||= Quandl::Client::Dataset::Data.new( id: id )
139
+ end
140
+
141
+ def dataset_data?
142
+ @dataset_data.is_a?(Quandl::Client::Dataset::Data)
143
+ end
144
+
145
+ def reload
146
+ @dataset_data = nil
147
+ @data_scope = nil
148
+ @full_code = nil
149
+ end
150
+
151
+ protected
152
+
153
+ def data_should_be_valid!
154
+ if data? && !data.valid?
155
+ data.errors.each{|k,v| self.errors.add( k,v ) }
156
+ return false
157
+ end
158
+ true
159
+ end
160
+
161
+ def dataset_data_should_be_valid!
162
+ if dataset_data? && !dataset_data.valid?
163
+ dataset_data.errors.each{|k,v| self.errors.add( k,v ) }
164
+ return false
165
+ end
166
+ true
167
+ end
168
+
169
+ def source_code_should_exist!
170
+ if source_code.present?
171
+ Source.cached[source_code] = Source.find(source_code) unless Source.cached.has_key?(source_code)
172
+ source = Source.cached[source_code]
173
+ self.errors.add( :source_code, "Could not find a source with the source_code '#{source_code}'" ) if source.blank? || source.code.blank?
174
+ return false
175
+ end
176
+ true
177
+ end
178
+
179
+ def ambiguous_code_requires_source_code!
180
+ if code.to_s.numeric? && source_code.blank?
181
+ message = %Q{Pure numerical codes like "#{code}" are not allowed unless you include a source code. Do this:\nsource_code: <USERNAME>\ncode: #{code}}
182
+ self.errors.add( :data, message )
183
+ return false
184
+ end
185
+ true
186
+ end
187
+
188
+ def data_columns_should_not_exceed_column_names!
189
+ if errors.size == 0 && data? && data.present? && column_names.present? && data.first.count != column_names.count
190
+ self.errors.add( :data, "You may not change the number of columns in a dataset. This dataset has #{column_names.count} columns but you tried to send #{data.first.count} columns." )
191
+ return false
192
+ end
193
+ true
194
+ end
195
+
196
+ def data_rows_should_have_equal_columns!
197
+ # skip validation unless data is present
198
+ return true unless data? && data.present?
199
+ # use first row as expected column count
200
+ column_count = data[0].count
201
+ # check each row
202
+ data.each_with_index do |row, index|
203
+ # the row is valid if it's count matches the first row's count
204
+ next if row.count == column_count
205
+ # the row is invalid if the count is mismatched
206
+ self.errors.add( :data, "Unexpected number of points in this row:\n#{row.join(',')}\nFound #{row.size-1} but expected #{data[0].size-1} based on precedent from the first row (#{data[0].join(',')})" )
207
+ # return validation failure
208
+ return false
209
+ end
210
+ true
211
+ end
212
+
213
+ def data_row_count_should_match_column_count!
214
+ # skip validation unless data and column_names present
215
+ return true unless data? && data.present? && column_names.present?
216
+ # count the number of expected columns
217
+ column_count = column_names.count
218
+ # check each row
219
+ data.each_with_index do |row, index|
220
+ # the row is valid if it's count matches the first row's count
221
+ next if row.count == column_count
222
+ # the row is invalid if the count is mismatched
223
+ self.errors.add( :data, "Unexpected number of points in this row:\n#{row.join(',')}\nFound #{row.size-1} but expected #{column_names.count-1} based on precedent from the header row (#{column_names.join(',')})" )
224
+ # return validation failure
225
+ return false
226
+ end
227
+ true
228
+ end
229
+
230
+ def save_dataset_data
231
+ return if (!saved? && id.blank?)
232
+ return if !data? || data.blank?
233
+
234
+ dataset_data.id = id
235
+ dataset_data.data = data.to_csv
236
+ dataset_data.save
237
+ # update dataset's attributes with dataset_data's attributes
238
+ attributes.each{|k,v| attributes[k] = dataset_data.attributes[k] if dataset_data.attributes.has_key?(k) }
239
+ # update dataset errors with dataset_data
240
+ @metadata[:status] = dataset_data.status unless dataset_data.saved?
241
+ # inherit_errors(dataset_data) unless dataset_data.saved?
242
+ end
243
+
244
+ def inherit_errors(object)
245
+ return unless object.respond_to?(:response_errors) && object.response_errors.respond_to?(:each)
246
+ object.response_errors.each do |key, messages|
247
+ if messages.respond_to?(:each)
248
+ messages.each{|message| errors.add(key, message) }
249
+ end
250
+ end
251
+ @metadata[:status] = object.status
252
+ object
253
+ end
254
+
255
+ def enforce_required_formats
256
+ # self.data = Quandl::Data.new(data).to_csv
257
+ self.source_code = self.source_code.to_s.upcase
258
+ self.code = self.code.to_s.upcase
259
+ self.locations_attributes = locations_attributes.to_json if locations_attributes.respond_to?(:to_json) && !locations_attributes.kind_of?(String)
260
+ end
261
+
246
262
  end