quandl_operation 0.1.18 → 0.1.19
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 +4 -4
- data/lib/quandl/operation/qdformat.rb +15 -117
- data/lib/quandl/operation/qdformat/dump.rb +49 -0
- data/lib/quandl/operation/qdformat/load.rb +53 -0
- data/lib/quandl/operation/qdformat/node.rb +49 -0
- data/lib/quandl/operation/version.rb +1 -1
- data/spec/lib/quandl/operation/qdformat_spec.rb +43 -33
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21f4883192fd7504a13a091e6215b64d839359f8
|
4
|
+
data.tar.gz: 542095e6c669ebb97ac8c34543e40011a95847d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3163d4f4952ddded01c8d8bbeab2c2680fadd9ef451728397ce90e0e49d71734a82153ca0b8e72e977ddf2536fe9969620ca9ba4092aae2ed46023220f8e331
|
7
|
+
data.tar.gz: 10e238077f7a8e08010ccc28561709451cd319b4cbd7e2a871c208b959350e0f92227de42d87d2dba5c2e6d11d469bd32a57f344c7adf04b014c5ef9f385d7bd
|
@@ -1,126 +1,24 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
require 'quandl/operation/qdformat/dump'
|
5
|
+
require 'quandl/operation/qdformat/load'
|
6
|
+
require 'quandl/operation/qdformat/node'
|
7
|
+
|
1
8
|
class Quandl::Operation::QDFormat
|
2
|
-
|
3
|
-
attr_accessor :source_code, :code, :name, :description, :data, :headers
|
4
|
-
|
5
9
|
class << self
|
6
10
|
|
7
|
-
def
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def parse(output)
|
12
|
-
datasets = []
|
13
|
-
attributes = {}
|
14
|
-
# for each line
|
15
|
-
output.each_line do |line|
|
16
|
-
# strip whitespace
|
17
|
-
line = line.strip.rstrip
|
18
|
-
|
19
|
-
# skip blank
|
20
|
-
if line.blank?
|
21
|
-
next
|
22
|
-
|
23
|
-
# - denotes new dataset
|
24
|
-
elsif line[0] == '-'
|
25
|
-
# append current dataset
|
26
|
-
datasets << attributes unless attributes.blank?
|
27
|
-
# reset attributes for next dataset
|
28
|
-
attributes = {}
|
29
|
-
|
30
|
-
# without the data key we're still adding metadata
|
31
|
-
elsif !attributes.has_key?(:data)
|
32
|
-
# for each rule
|
33
|
-
matched = false
|
34
|
-
rules.each do |name, rule|
|
35
|
-
# test line
|
36
|
-
m = line.match(rule)
|
37
|
-
# if the rule matches
|
38
|
-
if !matched && m.present?
|
39
|
-
matched = true
|
40
|
-
case name
|
41
|
-
when :full_code then attributes[:full_code] = line
|
42
|
-
when :attribute then attributes[m[1].to_sym] = m[2]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
# if no match was found for this line it must be data
|
47
|
-
attributes[:data] = line if !matched
|
48
|
-
# otherwise we're adding data
|
49
|
-
else
|
50
|
-
attributes[:data] += "\n" + line
|
51
|
-
end
|
52
|
-
end
|
53
|
-
datasets << attributes unless attributes.blank?
|
54
|
-
datasets.collect{|attrs| self.new(attrs) }
|
11
|
+
def load(input)
|
12
|
+
Quandl::Operation::QDFormat::Load.from_string(input)
|
55
13
|
end
|
56
14
|
|
57
|
-
def
|
58
|
-
|
59
|
-
full_code: /^([A-Z0-9_]+)\/([A-Z0-9_]+)$/,
|
60
|
-
attribute: /^([a-z0-9_]+): (.+)/
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
def initialize(attrs)
|
67
|
-
assign_attributes(attrs)
|
68
|
-
end
|
69
|
-
|
70
|
-
def assign_attributes(attrs)
|
71
|
-
attrs.each do |key, value|
|
72
|
-
self.send("#{key}=", value) if self.respond_to?(key)
|
15
|
+
def load_file(file_path)
|
16
|
+
Quandl::Operation::QDFormat::Load.from_file(input)
|
73
17
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
{ name: name, source_code: source_code, code: code, description: description, column_names: headers, data: data }
|
78
|
-
end
|
79
|
-
|
80
|
-
def inspect
|
81
|
-
"<##{self.class.name}" +
|
82
|
-
[:full_code, :name, :description, :headers].inject({}){|m,k| m[k] = self.send(k); m }.to_s +
|
83
|
-
" >"
|
84
|
-
end
|
85
|
-
|
86
|
-
def headers=(names)
|
87
|
-
names = names.split(",").collect(&:strip) if names.is_a?(String)
|
88
|
-
@headers = Array(names).flatten
|
89
|
-
end
|
90
|
-
def headers_as_qdf
|
91
|
-
headers.join(', ') if headers.is_a?(Array)
|
92
|
-
end
|
93
|
-
|
94
|
-
def full_code=(value)
|
95
|
-
value = value.split('/')
|
96
|
-
self.source_code = value[0]
|
97
|
-
self.code = value[1]
|
98
|
-
end
|
99
|
-
|
100
|
-
def full_code
|
101
|
-
[source_code, code].join('/')
|
102
|
-
end
|
103
|
-
|
104
|
-
def data_as_qdf
|
105
|
-
o = data
|
106
|
-
o = o.to_a if o.respond_to?(:to_a)
|
107
|
-
o = o.collect(&:to_csv).join if o.respond_to?(:to_csv) && o.first.is_a?(Array)
|
108
|
-
o = o.to_csv if o.respond_to?(:to_csv)
|
109
|
-
o
|
110
|
-
end
|
111
|
-
|
112
|
-
def data=(rows)
|
113
|
-
@data = rows
|
114
|
-
end
|
115
|
-
|
116
|
-
def to_qdf
|
117
|
-
output = [full_code]
|
118
|
-
[:name, :description].each do |attr_name|
|
119
|
-
output << "#{attr_name}: #{self.send(attr_name)}" if self.send(attr_name).present?
|
18
|
+
|
19
|
+
def dump(nodes)
|
20
|
+
Quandl::Operation::QDFormat::Dump.nodes(nodes)
|
120
21
|
end
|
121
|
-
|
122
|
-
output << data_as_qdf
|
123
|
-
output.join("\n")
|
22
|
+
|
124
23
|
end
|
125
|
-
|
126
24
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Quandl
|
2
|
+
module Operation
|
3
|
+
class QDFormat
|
4
|
+
|
5
|
+
class Dump
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def nodes(*args)
|
10
|
+
Array(args).flatten.collect{|r| node(r) }.join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
def node(node)
|
14
|
+
self.new(node).to_qdf
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :node
|
20
|
+
|
21
|
+
def initialize(r)
|
22
|
+
self.node = r
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_qdf
|
26
|
+
[attributes, column_names, data].compact.join
|
27
|
+
end
|
28
|
+
|
29
|
+
def attributes
|
30
|
+
[:source_code, :code, :name, :description].
|
31
|
+
inject({}){|m,k| m[k.to_s] = node.send(k) unless node.send(k).blank?; m }.
|
32
|
+
to_yaml[4..-1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def data
|
36
|
+
data = node.data.is_a?(Array) ? node.data.collect(&:to_csv).join : node.data
|
37
|
+
data = data.to_csv if data.respond_to?(:to_csv)
|
38
|
+
data
|
39
|
+
end
|
40
|
+
|
41
|
+
def column_names
|
42
|
+
node.column_names.to_csv if node.column_names.present?
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Quandl::Operation::QDFormat::Load
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def from_file(path)
|
6
|
+
from_string(File.read(path).strip)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_string(input)
|
10
|
+
nodes = []
|
11
|
+
input.each_line do |line|
|
12
|
+
# strip whitespace
|
13
|
+
line = line.strip.rstrip
|
14
|
+
# ignore comments and blank lines
|
15
|
+
next if line[0] == '#' || line.blank?
|
16
|
+
# code_format denotes the start of a new node
|
17
|
+
nodes << { attributes: '', data: '' } if line =~ code_format
|
18
|
+
# attribute_format denotes an attribute
|
19
|
+
if line =~ attribute_format
|
20
|
+
# add the attribute to attributes
|
21
|
+
nodes[-1][:attributes] += "#{line}\n"
|
22
|
+
# otherwise it must be data
|
23
|
+
else
|
24
|
+
nodes[-1][:data] += "#{line}\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
# append the current node
|
28
|
+
nodes = parse_nodes(nodes)
|
29
|
+
nodes
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def parse_nodes(nodes)
|
36
|
+
nodes.collect do |node|
|
37
|
+
node[:attributes] = YAML.load( node[:attributes] )
|
38
|
+
node[:attributes][:data] = CSV.parse(node[:data])
|
39
|
+
Quandl::Operation::QDFormat::Node.new(node[:attributes])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def code_format
|
44
|
+
/^code: (.+)/
|
45
|
+
end
|
46
|
+
|
47
|
+
def attribute_format
|
48
|
+
/^([a-z0-9_]+): (.+)/
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Quandl::Operation::QDFormat::Node
|
2
|
+
|
3
|
+
ATTRIBUTES = :source_code, :code, :name, :description, :column_names
|
4
|
+
attr_accessor *ATTRIBUTES
|
5
|
+
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
def initialize(attrs)
|
9
|
+
assign_attributes(attrs)
|
10
|
+
end
|
11
|
+
|
12
|
+
def assign_attributes(attrs)
|
13
|
+
attrs.each do |key, value|
|
14
|
+
self.send("#{key}=", value) if self.respond_to?(key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def attributes
|
19
|
+
ATTRIBUTES.inject({}){|m,k| m[k] = self.send(k); m }
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"<##{self.class.name} #{attributes.to_s} >"
|
24
|
+
end
|
25
|
+
|
26
|
+
def full_code=(value)
|
27
|
+
value = value.split('/')
|
28
|
+
self.source_code = value[0]
|
29
|
+
self.code = value[1]
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_code
|
33
|
+
[source_code, code].join('/')
|
34
|
+
end
|
35
|
+
|
36
|
+
def data=(rows)
|
37
|
+
self.column_names = rows.shift unless rows.first.collect{|r| r.to_s.numeric? }.include?(true)
|
38
|
+
@data = rows
|
39
|
+
end
|
40
|
+
|
41
|
+
def column_names=(names)
|
42
|
+
@column_names = Array(names).flatten.collect{|n| n.strip.rstrip }
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_qdf
|
46
|
+
Quandl::Operation::QDFormat::Dump.node(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -4,61 +4,71 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Quandl::Operation::QDFormat do
|
6
6
|
|
7
|
-
let(:
|
8
|
-
let(:name){ 'name: Test dataset name' }
|
9
|
-
let(:description){ 'description: Dataset description' }
|
10
|
-
let(:headers){ 'headers: Date, value, high, low' }
|
11
|
-
let(:data){ "2013-11-20,9.99470588235294,11.003235294117646,14.00164705882353\n2013-11-19,10.039388096885814,,14.09718770934256\n2013-11-18,10.03702588792184,11.040801329322205,14.148600982164867\n2013-11-16,10.019903902583621,10.99988541851354,14.186053161235304\n2013-11-15,9.98453953586862,10.922239168500502,\n2013-11-14,10.004508614940358,10.894612328250766,\n2013-11-13,,10.877309120435308,14.187437960548612\n2013-11-12,,10.838918617657301,14.22499294338536\n2013-11-11,9.965116185761039,10.827442115591547,14.178970907392053\n2013-11-09,9.881291973139637,10.924889094631869" }
|
12
|
-
|
13
|
-
let(:output){
|
7
|
+
let(:qdf_dataset){
|
14
8
|
%Q{
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
-
|
23
|
-
-
|
24
|
-
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
9
|
+
# YAML metadata
|
10
|
+
code: DATASET_CODE
|
11
|
+
source_code: SOURCE_CODE
|
12
|
+
name: Test Dataset Name 1
|
13
|
+
description: Here is a description with multiple lines.\\n This is the second line.
|
14
|
+
# CSV data
|
15
|
+
Date, Value, High, Low
|
16
|
+
2013-11-20,9.99470588235294,11.003235294117646,14.00164705882353
|
17
|
+
2013-11-19,10.039388096885814,,14.09718770934256
|
18
|
+
|
19
|
+
# Second dataset
|
20
|
+
code: DATASET_CODE_2
|
21
|
+
source_code: SOURCE_CODE_2
|
22
|
+
name: Test Dataset Name 2
|
23
|
+
description: Here is a description with multiple lines.
|
24
|
+
# CSV data
|
25
|
+
Date, Value, High, Low
|
26
|
+
2013-11-20,9.99470588235294,11.003235294117646,14.00164705882353
|
27
|
+
2013-11-19,10.039388096885814,,14.09718770934256
|
28
|
+
2013-11-18,11.039388096885814,,15.09718770934256
|
30
29
|
}
|
31
30
|
}
|
32
|
-
let(:collection){ Quandl::Operation::QDFormat.parse(output) }
|
33
31
|
|
34
|
-
|
32
|
+
let(:collection){ Quandl::Operation::QDFormat.load(qdf_dataset) }
|
33
|
+
|
34
|
+
describe ".load" do
|
35
35
|
|
36
36
|
subject{ collection }
|
37
|
-
|
37
|
+
|
38
38
|
its(:count){ should eq 2 }
|
39
39
|
|
40
40
|
describe "#first" do
|
41
41
|
subject{ collection.first }
|
42
42
|
|
43
|
-
it{ should be_a Quandl::Operation::QDFormat }
|
43
|
+
it{ should be_a Quandl::Operation::QDFormat::Node }
|
44
44
|
its(:source_code){ should eq 'SOURCE_CODE' }
|
45
45
|
its(:code){ should eq 'DATASET_CODE' }
|
46
|
-
its(:name){ should eq 'Test
|
47
|
-
its(:description){ should eq '
|
48
|
-
its(:
|
49
|
-
its(:data){ should eq
|
46
|
+
its(:name){ should eq 'Test Dataset Name 1' }
|
47
|
+
its(:description){ should eq 'Here is a description with multiple lines.\n This is the second line.' }
|
48
|
+
its(:column_names){ should eq ['Date', 'Value', 'High', 'Low'] }
|
49
|
+
its(:data){ should eq [
|
50
|
+
["2013-11-20", "9.99470588235294", "11.003235294117646", "14.00164705882353"],
|
51
|
+
["2013-11-19", "10.039388096885814", nil, "14.09718770934256"]] }
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
describe "#to_qdf" do
|
54
56
|
subject{ collection.first }
|
55
|
-
|
57
|
+
|
58
|
+
its(:to_qdf){ should eq %Q{source_code: SOURCE_CODE
|
59
|
+
code: DATASET_CODE
|
60
|
+
name: Test Dataset Name 1
|
61
|
+
description: Here is a description with multiple lines.\\n This is the second line.
|
62
|
+
Date,Value,High,Low
|
63
|
+
2013-11-20,9.99470588235294,11.003235294117646,14.00164705882353
|
64
|
+
2013-11-19,10.039388096885814,,14.09718770934256
|
65
|
+
}}
|
56
66
|
|
57
67
|
context "data Array" do
|
58
68
|
let(:data){ [['2013-11-20',9.94,11.2],['2013-11-19',9.94,11.2],['2013-11-18',9.94,11.2]] }
|
59
|
-
subject{ Quandl::Operation::QDFormat.new( full_code: "TEST/OIL", data: data ) }
|
69
|
+
subject{ Quandl::Operation::QDFormat::Node.new( full_code: "TEST/OIL", data: data ) }
|
60
70
|
|
61
|
-
its(:to_qdf){ should eq
|
71
|
+
its(:to_qdf){ should eq "source_code: TEST\ncode: OIL\n2013-11-20,9.94,11.2\n2013-11-19,9.94,11.2\n2013-11-18,9.94,11.2\n" }
|
62
72
|
|
63
73
|
end
|
64
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quandl_operation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Hilscher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -149,6 +149,9 @@ files:
|
|
149
149
|
- lib/quandl/operation/core_ext/time.rb
|
150
150
|
- lib/quandl/operation/parse.rb
|
151
151
|
- lib/quandl/operation/qdformat.rb
|
152
|
+
- lib/quandl/operation/qdformat/dump.rb
|
153
|
+
- lib/quandl/operation/qdformat/load.rb
|
154
|
+
- lib/quandl/operation/qdformat/node.rb
|
152
155
|
- lib/quandl/operation/transform.rb
|
153
156
|
- lib/quandl/operation/version.rb
|
154
157
|
- quandl_operation.gemspec
|