quandl_cassinatra 0.2.2 → 0.2.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.
Files changed (33) hide show
  1. data/README.md +8 -8
  2. data/UPGRADE.md +10 -0
  3. data/lib/quandl/cassinatra.rb +9 -15
  4. data/lib/quandl/cassinatra/base.rb +58 -0
  5. data/lib/quandl/cassinatra/base/attributes.rb +51 -0
  6. data/lib/quandl/cassinatra/base/model.rb +14 -0
  7. data/lib/quandl/cassinatra/base/search.rb +96 -0
  8. data/lib/quandl/cassinatra/{concerns/properties.rb → base/validation.rb} +9 -31
  9. data/lib/quandl/cassinatra/models/dataset.rb +33 -0
  10. data/lib/quandl/cassinatra/models/dataset/attributes.rb +61 -0
  11. data/lib/quandl/cassinatra/models/dataset/searchable.rb +68 -0
  12. data/lib/quandl/cassinatra/models/multiset.rb +27 -0
  13. data/lib/quandl/cassinatra/version.rb +1 -1
  14. data/lib/quandl/her/remove_method_data.rb +11 -0
  15. data/spec/factories/dataset.rb +1 -1
  16. data/spec/quandl/cassinatra/dataset/attributes_spec.rb +27 -0
  17. data/spec/quandl/cassinatra/dataset/delete_spec.rb +2 -2
  18. data/spec/quandl/cassinatra/dataset/persistence_spec.rb +26 -25
  19. data/spec/quandl/cassinatra/dataset/trim_spec.rb +2 -2
  20. data/spec/quandl/cassinatra/multiset_spec.rb +23 -14
  21. data/spec/spec_helper.rb +3 -1
  22. metadata +14 -14
  23. data/lib/quandl/cassinatra/concerns.rb +0 -17
  24. data/lib/quandl/cassinatra/concerns/search.rb +0 -26
  25. data/lib/quandl/cassinatra/core_ext.rb +0 -1
  26. data/lib/quandl/cassinatra/core_ext/string.rb +0 -8
  27. data/lib/quandl/cassinatra/her.rb +0 -32
  28. data/lib/quandl/cassinatra/model.rb +0 -27
  29. data/lib/quandl/cassinatra/model/dataset.rb +0 -56
  30. data/lib/quandl/cassinatra/model/dataset/searchable.rb +0 -96
  31. data/lib/quandl/cassinatra/model/dataset_attribute.rb +0 -13
  32. data/lib/quandl/cassinatra/model/multiset.rb +0 -36
  33. data/lib/quandl/her/patch.rb +0 -30
data/README.md CHANGED
@@ -11,7 +11,7 @@ include Quandl::Cassinatra
11
11
  ```
12
12
 
13
13
 
14
- ### Quandl::Cassinatra::Model::Dataset
14
+ ### Quandl::Cassinatra::Dataset
15
15
 
16
16
  #### Find / Scope
17
17
 
@@ -19,8 +19,8 @@ include Quandl::Cassinatra
19
19
 
20
20
  require 'quandl/cassinatra'
21
21
 
22
- d = Quandl::Cassinatra::Model::Dataset.limit(10).transform(:rdiff).collapse(:weekly).find(293)
23
- d.data_table
22
+ d = Quandl::Cassinatra::Dataset.limit(10).transform(:rdiff).collapse(:weekly).find(293)
23
+ d.data
24
24
  => [...]
25
25
 
26
26
  d.column_ids
@@ -41,25 +41,25 @@ d.updated_at
41
41
 
42
42
  require 'quandl/cassinatra'
43
43
 
44
- d = Quandl::Cassinatra::Model::Dataset.new
44
+ d = Quandl::Cassinatra::Dataset.new
45
45
  d.id = 5893853
46
46
  d.data = Quandl::Fabricate::Data::Table.rand(rows: 10, columns: 4, nils: false).to_csv
47
47
  d.save
48
48
 
49
- d = Quandl::Cassinatra::Model::Dataset.find(5893853)
50
- d.data_table
49
+ d = Quandl::Cassinatra::Dataset.find(5893853)
50
+ d.data
51
51
  => [...]
52
52
 
53
53
  ```
54
54
 
55
55
 
56
- ### Quandl::Cassinatra::Model::Multiset
56
+ ### Quandl::Cassinatra::Multiset
57
57
 
58
58
  ```ruby
59
59
 
60
60
  require 'quandl/cassinatra'
61
61
 
62
- m = Quandl::Cassinatra::Model::Multiset.with_columns('5893853.1,293.2').limit(10).collapse(:monthly)
62
+ m = Quandl::Cassinatra::Multiset.with_columns('5893853.1,293.2').limit(10).collapse(:monthly)
63
63
  m.data
64
64
  => [...]
65
65
 
data/UPGRADE.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.2.3
2
+
3
+ * multiset#reload
4
+ * revise multiset
5
+ * split dataset into attributes.
6
+ * fetch data once
7
+ * Cassinatra::Dataset#data
8
+ * feature/refactor_dataset
9
+
10
+
1
11
  ## 0.2.2
2
12
 
3
13
  * delete uses destroy_existing
@@ -1,26 +1,20 @@
1
1
  require "quandl/cassinatra/version"
2
2
 
3
- require 'quandl/logger'
4
-
5
- require "active_support"
6
- require "active_support/inflector"
7
- require "active_support/core_ext/hash"
8
- require "active_support/core_ext/object"
9
-
10
- require 'her'
11
- require 'quandl/her/patch'
12
3
  require 'scope_composer'
4
+ require 'her'
5
+ require 'quandl/her/remove_method_data'
6
+ require 'quandl/logger'
13
7
  require "quandl/data"
14
8
 
15
- require "quandl/cassinatra/core_ext"
16
9
  require 'quandl/cassinatra/middleware'
17
-
18
- require 'quandl/cassinatra/concerns'
19
- require 'quandl/cassinatra/her'
20
- require 'quandl/cassinatra/model'
10
+ require 'quandl/cassinatra/base'
11
+ require 'quandl/cassinatra/models/dataset'
12
+ require 'quandl/cassinatra/models/multiset'
21
13
 
22
14
  module Quandl
23
15
  module Cassinatra
24
- include Quandl::Cassinatra::Model
16
+ def self.use(url)
17
+ Quandl::Cassinatra::Base.use(url)
18
+ end
25
19
  end
26
20
  end
@@ -0,0 +1,58 @@
1
+ require "active_support"
2
+ require "active_support/inflector"
3
+ require "active_support/core_ext/hash"
4
+ require "active_support/core_ext/object"
5
+
6
+ require 'quandl/cassinatra/base/model'
7
+ require 'quandl/cassinatra/base/attributes'
8
+ require 'quandl/cassinatra/base/validation'
9
+ require 'quandl/cassinatra/base/search'
10
+
11
+ class Quandl::Cassinatra::Base
12
+
13
+ class << self
14
+
15
+ attr_accessor :url
16
+
17
+ def use(url)
18
+ self.url = url
19
+ models_use_her_api!
20
+ end
21
+
22
+ def her_api
23
+ Her::API.new.setup url: url do |c|
24
+ c.use Faraday::Request::UrlEncoded
25
+ c.use Quandl::Cassinatra::Middleware::ParseJSON
26
+ c.use Faraday::Adapter::NetHttp
27
+ end
28
+ end
29
+
30
+ def url
31
+ @url ||= 'http://localhost:9292/'
32
+ end
33
+
34
+ def inherited(subclass)
35
+ # remember models that inherit from base
36
+ models << subclass unless models.include?(subclass)
37
+ # include model behaviour
38
+ subclass.class_eval do
39
+ include Quandl::Cassinatra::Base::Model
40
+ include Quandl::Cassinatra::Base::Attributes
41
+ include Quandl::Cassinatra::Base::Validation
42
+ include Quandl::Cassinatra::Base::Search
43
+ end
44
+ end
45
+
46
+ def models
47
+ @@models ||= []
48
+ end
49
+
50
+ protected
51
+
52
+ def models_use_her_api!
53
+ models.each{|m| m.use_api( her_api ) }
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,51 @@
1
+ class Quandl::Cassinatra::Base
2
+ module Attributes
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ def find_existing(id)
9
+ self.new(id: id)
10
+ end
11
+
12
+ end
13
+
14
+ def inspect
15
+ "#{self.class.name} " + attributes.inspect
16
+ end
17
+
18
+ def imprint(record)
19
+ # ensure matching classes
20
+ raise(ArgumentError, "record must be kind_of?(#{self.class})") unless record.kind_of?( self.class )
21
+ # copy variables
22
+ copy_instance_variables(record)
23
+ end
24
+
25
+ protected
26
+
27
+ def copy_instance_variables(record)
28
+ # copy attributes if record was found
29
+ @attributes = record.attributes if record.exists?
30
+ # copy metadata and errors
31
+ [:metadata, :response_errors].each do |ivar|
32
+ self.instance_variable_set("@#{ivar}", record.instance_variable_get("@#{ivar}") )
33
+ end
34
+ self
35
+ end
36
+
37
+ def write_attributes(hash)
38
+ @attributes = hash
39
+ end
40
+
41
+ def write_attribute(attribute, value)
42
+ self.send(:"#{attribute}_will_change!") if @attributes[:"#{attribute}"] != value
43
+ @attributes[:"#{attribute}"] = value
44
+ end
45
+
46
+ def read_attribute(attribute)
47
+ @attributes[:"#{attribute}"]
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,14 @@
1
+ class Quandl::Cassinatra::Base
2
+ module Model
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ include Her::Model
9
+ use_api Quandl::Cassinatra::Base.her_api
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,96 @@
1
+ class Quandl::Cassinatra::Base
2
+ module Search
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ include ScopeComposer::Model
9
+
10
+ has_scope_composer
11
+
12
+ scope.class_eval do
13
+
14
+ def fetch_once
15
+ @fetch_once ||= fetch
16
+ end
17
+
18
+ def fetch
19
+ result = find(attributes[:id])
20
+ result = references.imprint( result ) unless references.nil?
21
+ result
22
+ end
23
+
24
+ def find(id)
25
+ begin
26
+ t1 = Time.now
27
+ result = self.class.parent.where(attributes).find(id)
28
+ Quandl::Logger.debug "#{self.class.name}.where(#{attributes.to_param if attributes.respond_to?(:to_param)}).find(#{id}) (#{t1.elapsed_ms})"
29
+ rescue => error
30
+ Quandl::Logger.error "#{self.class.name}.find #{error}"
31
+ end
32
+ result = self.class.parent.new(id: id) if result.nil?
33
+ result
34
+ end
35
+
36
+ def references(*args)
37
+ return @references if args.first.nil?
38
+ @references = args.first
39
+ attributes[:id] = @references.id
40
+ self
41
+ end
42
+
43
+ protected
44
+
45
+ def format_trim_date(date, start_or_end)
46
+ # parse
47
+ date = parse_date(date)
48
+ # format
49
+ if date.is_a?(Date)
50
+ date = date.send("#{start_or_end}_of_frequency", collapse) if collapse.present?
51
+ date.jd
52
+ else
53
+ nil
54
+ end
55
+ end
56
+
57
+ def parse_date( date )
58
+ begin
59
+ date = Date.jd(date.to_i) if date.kind_of?(String) && numeric?(date)
60
+ date = Date.jd(date) if date.is_a?(Integer)
61
+ date = Date.parse(date) if date.is_a?(String) && date =~ /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/
62
+ date
63
+ rescue
64
+ nil
65
+ end
66
+ end
67
+
68
+ def numeric?(string)
69
+ string = string.to_s
70
+ if string =~ /^\d+$/
71
+ true
72
+ else
73
+ Float(string).is_a?(Float) rescue false
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ def reload
82
+ # reset attributes
83
+ @attributes = { 'id' => self.id }
84
+ @metadata = {}
85
+ # return self
86
+ true
87
+ end
88
+
89
+ module ClassMethods
90
+ def scope_names
91
+ self.scope.scope_names
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -1,18 +1,10 @@
1
- module Quandl
2
- module Cassinatra
3
- module Concerns
1
+ class Quandl::Cassinatra::Base
2
+ module Validation
4
3
 
5
- module Properties
6
4
  extend ActiveSupport::Concern
7
5
 
8
6
  included do
9
-
10
- include Her::Model
11
- use_api Quandl::Cassinatra.her_api
12
7
 
13
- before_save :touch_save_time
14
- after_save :log_save_time
15
-
16
8
  before_save :halt_unless_valid!
17
9
 
18
10
  def valid_with_server?
@@ -42,6 +34,10 @@ module Properties
42
34
  status >= 200 && status <= 210
43
35
  end
44
36
 
37
+ def queried?
38
+ status > 0
39
+ end
40
+
45
41
  def status
46
42
  metadata[:status].to_i
47
43
  end
@@ -69,30 +65,12 @@ module Properties
69
65
  response_errors.present? ? { response_errors: response_errors } : {}
70
66
  end
71
67
 
72
-
73
68
  protected
74
69
 
75
70
  def halt_unless_valid!
76
71
  return false unless valid?
77
72
  end
78
-
79
- private
80
-
81
- def save_timer
82
- @save_timer
83
- end
84
-
85
- def touch_save_time
86
- @save_timer = Time.now
87
- end
88
-
89
- def log_save_time
90
- Quandl::Logger.info("#{self.class.name}.save (#{save_timer.elapsed_ms})")
91
- end
92
-
93
- end
94
- end
95
-
96
- end
97
- end
73
+
74
+ end
98
75
  end
76
+ end
@@ -0,0 +1,33 @@
1
+ class Quandl::Cassinatra::Dataset < Quandl::Cassinatra::Base
2
+
3
+ require 'quandl/cassinatra/models/dataset/searchable'
4
+ require 'quandl/cassinatra/models/dataset/attributes'
5
+
6
+ include Quandl::Cassinatra::Dataset::Searchable
7
+ include Quandl::Cassinatra::Dataset::Attributes
8
+
9
+ def rows_count
10
+ count_data
11
+ end
12
+
13
+ def count_data
14
+ @count_data ||= self.class.get("datasets/#{id}/count").attributes[:count]
15
+ end
16
+
17
+ def delete_data
18
+ # cant delete unsaved records
19
+ return false if new_record?
20
+ # delete and return success / failure
21
+ self.class.destroy_existing("#{id}/data").saved?
22
+ end
23
+
24
+ def delete_rows(*dates)
25
+ # cant delete unsaved records
26
+ return false if new_record?
27
+ # collect dates
28
+ query = { dates: Array(dates).flatten }.to_query
29
+ # delete and return success / failure
30
+ self.class.destroy_existing("#{id}/data/rows?#{query}").saved?
31
+ end
32
+
33
+ end
@@ -0,0 +1,61 @@
1
+ module Quandl::Cassinatra::Dataset::Attributes
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ end
8
+
9
+ included do
10
+
11
+ attributes :id, :data, :trim_start, :trim_end, :columns, :frequency,
12
+ :rows_count, :type, :updated_at, :created_at
13
+
14
+ end
15
+
16
+ def column_units
17
+ @column_units ||= columns.collect{|c| c['units'] } if columns.present?
18
+ end
19
+
20
+ def column_names
21
+ @column_names ||= columns.collect{|c| c['name'] } if columns.present?
22
+ end
23
+
24
+ def column_ids
25
+ @column_ids ||= columns.collect{|c| c['id'] } if columns.present?
26
+ end
27
+
28
+ def trim_start
29
+ @trim_start ||= parse_julian_date( read_attribute(:trim_start) )
30
+ end
31
+
32
+ def trim_end
33
+ @trim_end ||= parse_julian_date( read_attribute(:trim_end) )
34
+ end
35
+
36
+ def created_at
37
+ @created_at ||= Time.parse(read_attribute(:created_at)) rescue nil
38
+ end
39
+
40
+ def updated_at
41
+ @updated_at ||= Time.parse(read_attribute(:updated_at)) rescue nil
42
+ end
43
+
44
+ def reload
45
+ # reset instance variables
46
+ [:column_units, :column_names, :column_ids, :count_data, :scope,
47
+ :updated_at, :created_at, :trim_start, :trim_end
48
+ ].each{|n| instance_variable_set("@#{n}", nil) }
49
+ # onwards
50
+ super
51
+ end
52
+
53
+ protected
54
+
55
+ def parse_julian_date(date)
56
+ date = date.to_i unless date.is_a?(Integer)
57
+ date = ( date > 0 ) ? Date.jd(date) : nil
58
+ date
59
+ end
60
+
61
+ end
@@ -0,0 +1,68 @@
1
+ module Quandl::Cassinatra::Dataset::Searchable
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def search_scopes
8
+ @search_scopes ||+ search_scope.scopes.keys
9
+ end
10
+
11
+ end
12
+
13
+ included do
14
+
15
+ scope.class_eval do
16
+ delegate :each, :collect, :to_a, :to_h, :count, :inspect, :[], to: :to_table, allow_nil: true
17
+ delegate *Quandl::Data::Table.forwardable_methods, to: :to_table, allow_nil: true
18
+ end
19
+
20
+ scope_helper :to_table, -> { fetch_once.data }
21
+
22
+ scope :row, ->(v) { where( row: v.to_i ) }
23
+ scope :limit, ->(v) { where( limit: v.to_i ) }
24
+ scope :offset, ->(v) { where( offset: v.to_i ) }
25
+ scope :accuracy, ->(v) { where( accuracy: v.to_i ) }
26
+ scope :column, ->(v) { where( column: v.to_i ) }
27
+ scope :order, ->(dir) { where( order: (dir.to_sym == :asc) ? 'asc' : 'desc' ) }
28
+ scope :trim_start, ->(date) { where( trim_start: format_trim_date(date, :start)) }
29
+ scope :trim_end, ->(date) { where( trim_end: format_trim_date(date, :end)) }
30
+ scope :with_id, ->(value) { where( id: value.to_i )}
31
+ scope :transform, ->(value) { where( transform: value.to_sym ) if Quandl::Operation::Transform.valid_transformation?( value.try(:to_sym) ) }
32
+
33
+ scope :collapse, ->(value){
34
+ # set collapse
35
+ where( collapse: value ) if Quandl::Operation::Collapse.valid_collapse?( value.try(:to_sym) )
36
+ # reset trims to force them to edge of frequency
37
+ trim_start(trim_start) if trim_start
38
+ trim_end(trim_end) if trim_end
39
+ }
40
+
41
+ end
42
+
43
+ def data
44
+ return read_data if data?
45
+ return scope unless queried?
46
+ nil
47
+ end
48
+
49
+ def data=(value)
50
+ write_data(value)
51
+ end
52
+
53
+ def scope
54
+ @scope ||= self.class.scope.new.references( self )
55
+ end
56
+
57
+
58
+ protected
59
+
60
+ def read_data
61
+ Quandl::Data::Table.new( read_attribute(:data) )
62
+ end
63
+
64
+ def write_data(value )
65
+ write_attribute(:data, Quandl::Data::Table.new(value).to_csv )
66
+ end
67
+
68
+ end
@@ -0,0 +1,27 @@
1
+ class Quandl::Cassinatra::Multiset < Quandl::Cassinatra::Base
2
+
3
+ include Quandl::Cassinatra::Dataset::Searchable
4
+
5
+ # scope_helper :record, -> { find('multiset') }
6
+
7
+ scope :columns, ->(v){ where( columns: v ) }
8
+
9
+ attributes :id, :data, :trim_start, :trim_end, :columns, :frequency, :type, :updated_at, :created_at
10
+
11
+ def column_units
12
+ @column_units ||= columns.collect{|c| c['units'] }
13
+ end
14
+
15
+ def column_names
16
+ @column_names ||= columns.collect{|c| c['name'] }
17
+ end
18
+
19
+ def column_ids
20
+ @column_ids ||= columns.collect{|c| c['id'] }
21
+ end
22
+
23
+ def save
24
+ false
25
+ end
26
+
27
+ end
@@ -1,5 +1,5 @@
1
1
  module Quandl
2
2
  module Cassinatra
3
- VERSION = '0.2.2'
3
+ VERSION = '0.2.3'
4
4
  end
5
5
  end
@@ -0,0 +1,11 @@
1
+ require 'yajl'
2
+
3
+ module Her
4
+ module Model
5
+ # remove deprecated data method since cassinatra returns data: []
6
+ module DeprecatedMethods
7
+ remove_method( :data ) if method_defined?( :data )
8
+ remove_method( :data= ) if method_defined?( :data= )
9
+ end
10
+ end
11
+ end
@@ -2,7 +2,7 @@ FactoryGirl.define do
2
2
 
3
3
  factory :dataset do
4
4
  sequence(:id) { |n| (Time.now.to_f * 1000).to_i + n }
5
- data_table{ Quandl::Fabricate::Data::Table.rand( rows: 730, columns: 3, nils: false ) }
5
+ data{ Quandl::Fabricate::Data::Table.rand( rows: 730, columns: 3, nils: false ) }
6
6
  end
7
7
 
8
8
  end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Dataset do
5
+ subject{ Dataset.find_existing(1) }
6
+ its(:attributes){ should eq({ 'id' => 1 }) }
7
+ its(:id){ should eq 1 }
8
+
9
+ context "#reload" do
10
+ before(:each){ subject.reload }
11
+ its(:attributes){ should eq({ 'id' => 1 }) }
12
+ its(:id){ should eq 1 }
13
+ end
14
+
15
+ context "#id" do
16
+ before(:each){ subject.id = 2 }
17
+ its(:attributes){ should eq({ 'id' => 2 }) }
18
+ its(:id){ should eq 2 }
19
+
20
+ context "#reload" do
21
+ before(:each){ subject.reload }
22
+ its(:attributes){ should eq({ 'id' => 2 }) }
23
+ its(:id){ should eq 2 }
24
+ end
25
+
26
+ end
27
+ end
@@ -17,14 +17,14 @@ describe Dataset do
17
17
 
18
18
  describe "#delete_rows" do
19
19
 
20
- let(:dates_slice){ dataset.data_table.to_h.keys[10..19] }
20
+ let(:dates_slice){ dataset.data.to_h.keys[10..19] }
21
21
 
22
22
  before(:each){ subject.delete_rows( dates_slice ) }
23
23
 
24
24
  its(:status){ should eq 200 }
25
25
 
26
26
  it "data count should be 720" do
27
- Dataset.find( dataset.id ).data_table.count.should eq 720
27
+ Dataset.find( dataset.id ).data.count.should eq 720
28
28
  end
29
29
 
30
30
  end
@@ -3,41 +3,42 @@ require 'spec_helper'
3
3
 
4
4
  describe Dataset do
5
5
 
6
- context "before save" do
7
-
8
- subject{ build(:dataset) }
6
+ let(:dataset){ build(:dataset) }
9
7
 
10
- it { should respond_to :columns_count }
11
- it { should respond_to :data }
12
- it { should respond_to :data_table }
13
-
14
- it "should have data" do
15
- subject.data_table.count.should eq 730
16
- end
17
-
18
- it "should have four columns" do
19
- subject.data_table[0].count.should eq 4
20
- end
21
-
8
+ subject{ dataset }
9
+
10
+ it { should respond_to :data }
11
+
12
+ describe "#data" do
13
+ subject{ dataset.data }
14
+ its(:count){ should eq 730 }
22
15
  end
23
16
 
24
- context "after save" do
17
+ context "#save" do
18
+
19
+ before(:each){ dataset.save }
25
20
 
26
- subject{ d = create(:dataset); Dataset.find(d.id) }
21
+ subject{ Dataset.find(dataset.id) }
27
22
 
23
+ its(:count_data){ should eq dataset.data.count }
24
+
25
+ describe "#columns" do
26
+ subject{ dataset.columns }
27
+ its(:count){ should eq 3 }
28
+ end
29
+
28
30
  describe "#column_ids" do
29
- it "should have 3 columns" do
30
- subject.column_ids.count.should eq 3
31
- end
32
- it "should each be present" do
33
- subject.column_ids.each{|cid| cid.present?.should be_true }
31
+ subject{ dataset.column_ids }
32
+ its(:count){ should eq 3 }
33
+
34
+ it "each should be present" do
35
+ subject.each{|cid| cid.present?.should be_true }
34
36
  end
35
37
  end
36
38
 
37
39
  describe "#data" do
38
- it "should have data" do
39
- subject.data.count.should eq 730
40
- end
40
+ subject{ dataset.data }
41
+ its(:count){ should eq 730 }
41
42
  end
42
43
 
43
44
  end
@@ -14,7 +14,7 @@ describe Dataset do
14
14
  context "after_save" do
15
15
  before(:each){ subject.save }
16
16
  it "should equal the last date" do
17
- subject.trim_start.should eq subject.data_table[-1][0]
17
+ subject.trim_start.should eq subject.data.to_date[-1][0]
18
18
  end
19
19
  end
20
20
  end
@@ -28,7 +28,7 @@ describe Dataset do
28
28
  context "after_save" do
29
29
  before(:each){ subject.save }
30
30
  it "should equal the first date" do
31
- subject.trim_end.should eq subject.data_table[0][0]
31
+ subject.trim_end.should eq subject.data.to_date[0][0]
32
32
  end
33
33
  end
34
34
  end
@@ -2,15 +2,26 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Multiset do
5
- let(:d1){ create(:dataset, data_table: Quandl::Fabricate::Data::Table.rand( rows: 10, columns: 4, nils: false ) ) }
6
- let(:d2){ create(:dataset, data_table: Quandl::Fabricate::Data::Table.rand( rows: 10, columns: 4, nils: false ) ) }
5
+ let(:d1){ create(:dataset, data: Quandl::Fabricate::Data::Table.rand( rows: 10, columns: 4, nils: false ) ) }
6
+ let(:d2){ create(:dataset, data: Quandl::Fabricate::Data::Table.rand( rows: 10, columns: 4, nils: false ) ) }
7
+ let(:multiset){ Multiset.find_existing('ephemeral') }
8
+ subject{ multiset }
9
+
10
+ describe "#data" do
11
+ subject{ multiset.data.columns("#{d1.id}.1,#{d2.id}.2") }
12
+
13
+ its(:count){ should eq 10 }
14
+ its(:to_h){ should be_present }
15
+ its(:to_a){ should be_present }
16
+
17
+ end
18
+
7
19
 
8
20
  context "given ascending columns" do
9
21
 
10
22
  it "should return the expected column_ids" do
11
- [d1, d2]
12
- m = Multiset.columns("#{d2.id.to_i}.1,#{d1.id.to_i}.1,#{d2.id.to_i}.3,#{d1.id.to_i}.2").to_dataset
13
- m.column_ids.should eq [
23
+ subject.data.columns("#{d2.id.to_i}.1,#{d1.id.to_i}.1,#{d2.id.to_i}.3,#{d1.id.to_i}.2").to_a
24
+ subject.column_ids.should eq [
14
25
  Dataset.find(d2.id).column_ids[0],
15
26
  Dataset.find(d1.id).column_ids[0],
16
27
  Dataset.find(d2.id).column_ids[2],
@@ -19,13 +30,11 @@ describe Multiset do
19
30
  end
20
31
 
21
32
  it "should return the expected columns" do
22
- [d1, d2]
23
- sleep 1
24
- m = Multiset.columns("#{d2.id.to_i}.1,#{d1.id.to_i}.1,#{d2.id.to_i}.3,#{d1.id.to_i}.2").to_dataset
25
- m.data_table[0][1].should eq d2.data_table[0][1]
26
- m.data_table[0][2].should eq d1.data_table[0][1]
27
- m.data_table[0][3].should eq d2.data_table[0][3]
28
- m.data_table[0][4].should eq d1.data_table[0][2]
33
+ subject.data.columns("#{d2.id.to_i}.1,#{d1.id.to_i}.1,#{d2.id.to_i}.3,#{d1.id.to_i}.2")
34
+ subject.data[0][1].should eq d2.data[0][1]
35
+ subject.data[0][2].should eq d1.data[0][1]
36
+ subject.data[0][3].should eq d2.data[0][3]
37
+ subject.data[0][4].should eq d1.data[0][2]
29
38
  end
30
39
 
31
40
  end
@@ -33,8 +42,8 @@ describe Multiset do
33
42
  context "given descending columns" do
34
43
 
35
44
  it "should return the expected columns" do
36
- m = Multiset.columns("#{d1.id.to_i}.2,#{d1.id.to_i}.1").to_dataset
37
- m.data_table[0][1].should_not eq m.data_table[0][2]
45
+ subject.data.columns("#{d1.id.to_i}.2,#{d1.id.to_i}.1")
46
+ subject.data[0][1].should_not eq subject.data[0][2]
38
47
  end
39
48
 
40
49
  end
@@ -15,4 +15,6 @@ require "quandl/fabricate"
15
15
  require "quandl/cassinatra"
16
16
  Quandl::Cassinatra.use 'http://192.168.33.10:8983/wikiposit_cassandra/'
17
17
  # Quandl::Cassinatra.use 'http://localhost:9292/'
18
- include Quandl::Cassinatra
18
+ include Quandl::Cassinatra
19
+
20
+ # binding.pry
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quandl_cassinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-10 00:00:00.000000000 Z
12
+ date: 2013-10-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -236,23 +236,22 @@ files:
236
236
  - Rakefile
237
237
  - UPGRADE.md
238
238
  - lib/quandl/cassinatra.rb
239
- - lib/quandl/cassinatra/concerns.rb
240
- - lib/quandl/cassinatra/concerns/properties.rb
241
- - lib/quandl/cassinatra/concerns/search.rb
242
- - lib/quandl/cassinatra/core_ext.rb
243
- - lib/quandl/cassinatra/core_ext/string.rb
244
- - lib/quandl/cassinatra/her.rb
239
+ - lib/quandl/cassinatra/base.rb
240
+ - lib/quandl/cassinatra/base/attributes.rb
241
+ - lib/quandl/cassinatra/base/model.rb
242
+ - lib/quandl/cassinatra/base/search.rb
243
+ - lib/quandl/cassinatra/base/validation.rb
245
244
  - lib/quandl/cassinatra/middleware.rb
246
245
  - lib/quandl/cassinatra/middleware/parse_json.rb
247
- - lib/quandl/cassinatra/model.rb
248
- - lib/quandl/cassinatra/model/dataset.rb
249
- - lib/quandl/cassinatra/model/dataset/searchable.rb
250
- - lib/quandl/cassinatra/model/dataset_attribute.rb
251
- - lib/quandl/cassinatra/model/multiset.rb
246
+ - lib/quandl/cassinatra/models/dataset.rb
247
+ - lib/quandl/cassinatra/models/dataset/attributes.rb
248
+ - lib/quandl/cassinatra/models/dataset/searchable.rb
249
+ - lib/quandl/cassinatra/models/multiset.rb
252
250
  - lib/quandl/cassinatra/version.rb
253
- - lib/quandl/her/patch.rb
251
+ - lib/quandl/her/remove_method_data.rb
254
252
  - quandl_cassinatra.gemspec
255
253
  - spec/factories/dataset.rb
254
+ - spec/quandl/cassinatra/dataset/attributes_spec.rb
256
255
  - spec/quandl/cassinatra/dataset/delete_spec.rb
257
256
  - spec/quandl/cassinatra/dataset/persistence_spec.rb
258
257
  - spec/quandl/cassinatra/dataset/searchable_spec.rb
@@ -286,6 +285,7 @@ specification_version: 3
286
285
  summary: Cassinatra rest orm.
287
286
  test_files:
288
287
  - spec/factories/dataset.rb
288
+ - spec/quandl/cassinatra/dataset/attributes_spec.rb
289
289
  - spec/quandl/cassinatra/dataset/delete_spec.rb
290
290
  - spec/quandl/cassinatra/dataset/persistence_spec.rb
291
291
  - spec/quandl/cassinatra/dataset/searchable_spec.rb
@@ -1,17 +0,0 @@
1
- require "active_support"
2
- require "active_support/inflector"
3
- require "active_support/core_ext/hash"
4
- require "active_support/core_ext/object"
5
-
6
- require 'quandl/cassinatra/concerns/search'
7
- require 'quandl/cassinatra/concerns/properties'
8
-
9
- module Quandl
10
- module Cassinatra
11
-
12
- module Concerns
13
-
14
- end
15
-
16
- end
17
- end
@@ -1,26 +0,0 @@
1
- module Quandl
2
- module Cassinatra
3
- module Concerns
4
-
5
- module Search
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
-
10
- include ScopeComposer::Model
11
-
12
- scope_composer_for :search
13
-
14
- search_helper :all, ->{ connection.where(attributes).fetch }
15
- search_helper :connection, -> { self.class.parent }
16
-
17
- search_scope.class_eval do
18
- delegate *Array.forwardable_methods, to: :all
19
- end
20
-
21
- end
22
- end
23
-
24
- end
25
- end
26
- end
@@ -1 +0,0 @@
1
- require "quandl/cassinatra/core_ext/string"
@@ -1,8 +0,0 @@
1
- class String
2
-
3
- def numeric?
4
- return true if self =~ /^\d+$/
5
- true if Float(self) rescue false
6
- end
7
-
8
- end
@@ -1,32 +0,0 @@
1
- module Quandl
2
- module Cassinatra
3
- class << self
4
-
5
- def use(url)
6
- self.rest_url = url
7
- end
8
-
9
- def her_api
10
- # setup api
11
- api = Her::API.new
12
- api.setup url: rest_url do |c|
13
- c.use Faraday::Request::UrlEncoded
14
- c.use Quandl::Cassinatra::Middleware::ParseJSON
15
- c.use Faraday::Adapter::NetHttp
16
- end
17
- end
18
-
19
- def rest_url
20
- @rest_url ||= 'http://localhost:9292/'
21
- end
22
-
23
- def rest_url=(url)
24
- url = "http://#{url}" if ( url =~ /^http:\/\// ) == nil
25
- @rest_url = url
26
- Model.use_api( her_api )
27
- @rest_url
28
- end
29
-
30
- end
31
- end
32
- end
@@ -1,27 +0,0 @@
1
- require 'quandl/cassinatra/model/dataset'
2
- require 'quandl/cassinatra/model/dataset_attribute'
3
- require 'quandl/cassinatra/model/multiset'
4
-
5
- module Quandl
6
- module Cassinatra
7
- module Model
8
- class << self
9
-
10
- def use_api(api)
11
- each{|k| k.use_api(api) }
12
- end
13
-
14
- def each(&block)
15
- models.each do |k|
16
- block.call(k)
17
- end
18
- end
19
-
20
- def models
21
- [Dataset, DatasetAttribute, Multiset]
22
- end
23
-
24
- end
25
- end
26
- end
27
- end
@@ -1,56 +0,0 @@
1
- require 'quandl/cassinatra/model/dataset/searchable'
2
-
3
- module Quandl
4
- module Cassinatra
5
- module Model
6
-
7
- class Dataset
8
-
9
- include Concerns::Properties
10
- include Searchable
11
-
12
- attributes :id, :data, :trim_start, :trim_end, :columns
13
-
14
- delegate :columns_count, :created_at, :frequency, :rows_count, :type, :updated_at, to: :dataset_attribute
15
-
16
- def column_units
17
- @column_units ||= columns.collect{|c| c['units'] }
18
- end
19
-
20
- def column_names
21
- @column_names ||= columns.collect{|c| c['name'] }
22
- end
23
-
24
- def column_ids
25
- @column_ids ||= columns.collect{|c| c['id'] }
26
- end
27
-
28
- def data_table
29
- @data_table ||= Data::Table.new( self.data || [] )
30
- end
31
- def data_table=(value)
32
- self.data = Data::Table.new(value).to_csv
33
- end
34
-
35
- def dataset_attribute(*args)
36
- return @dataset_attribute if @dataset_attribute
37
- # options
38
- options = args.extract_options!
39
- count = options[:count] == true
40
- # grab dataset_attribute
41
- @dataset_attribute = DatasetAttribute.where( count: count ).find(id)
42
- end
43
-
44
- def delete_data
45
- Dataset.destroy_existing("#{id.to_i}/data").status
46
- end
47
-
48
- def delete_rows(*dates)
49
- query = { dates: Array(dates).flatten }.to_query
50
- Dataset.destroy_existing("#{id.to_i}/data/rows?#{query}").status
51
- end
52
-
53
- end
54
- end
55
- end
56
- end
@@ -1,96 +0,0 @@
1
- module Quandl
2
- module Cassinatra
3
- module Model
4
- class Dataset
5
-
6
- module Searchable
7
-
8
- extend ActiveSupport::Concern
9
-
10
- module ClassMethods
11
-
12
- def search_scopes
13
- @search_scopes ||+ search_scope.scopes.keys
14
- end
15
-
16
- end
17
-
18
- included do
19
-
20
- include Quandl
21
- include ScopeComposer::Model
22
-
23
- scope_composer_for :search
24
-
25
- search_helper :column_ids, -> { dataset.column_ids }
26
- search_helper :data_table, -> { dataset.data_table }
27
-
28
- search_helper :dataset, -> { find(attributes[:id]) }
29
-
30
- search_scope.class_eval do
31
- delegate *Array.forwardable_methods, to: :data_table
32
- delegate *Data::Table.forwardable_methods, to: :data_table
33
- end
34
-
35
- search_scope :row, ->(v) { where( row: v.to_i ) }
36
- search_scope :limit, ->(v) { where( limit: v.to_i ) }
37
- search_scope :offset, ->(v) { where( offset: v.to_i ) }
38
- search_scope :accuracy, ->(v) { where( accuracy: v.to_i ) }
39
- search_scope :column, ->(v) { where( column: v.to_i ) }
40
- search_scope :order, ->(dir) { where( order: (dir.to_sym == :asc) ? 'asc' : 'desc' ) }
41
- search_scope :trim_start, ->(date) { where( trim_start: format_trim_date(date, :start)) }
42
- search_scope :trim_end, ->(date) { where( trim_end: format_trim_date(date, :end)) }
43
- search_scope :with_id, ->(value) { where( id: value.to_i )}
44
- search_scope :transform, ->(value) { where( transform: value.to_sym ) if Quandl::Operation::Transform.valid_transformation?( value.try(:to_sym) ) }
45
-
46
- search_scope :collapse, ->(value){
47
- # set collapse
48
- where( collapse: value ) if Quandl::Operation::Collapse.valid_collapse?( value.try(:to_sym) )
49
- # reset trims to force them to edge of frequency
50
- trim_start(trim_start) if trim_start
51
- trim_end(trim_end) if trim_end
52
- }
53
-
54
- search_helper :format_trim_date, ->( date, start_or_end ){
55
- # parse
56
- date = parse_date(date)
57
- # format
58
- if date.is_a?(Date)
59
- date = date.send("#{start_or_end}_of_frequency", collapse) if collapse.present?
60
- date.jd
61
- else
62
- nil
63
- end
64
- }
65
-
66
- search_helper :parse_date, ->( date ){
67
- begin
68
- date = Date.jd(date.to_i) if date.kind_of?(String) && date.numeric?
69
- date = Date.jd(date) if date.is_a?(Integer)
70
- date = Date.parse(date) if date.is_a?(String) && date =~ /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/
71
- date
72
- rescue
73
- nil
74
- end
75
- }
76
-
77
- search_helper :find, ->(id){
78
- begin
79
- t1 = Time.now
80
- result = self.class.parent.where(attributes).find(id)
81
- Quandl::Logger.debug "Quandl::Cassinatra::Dataset.where(#{attributes.to_param if attributes.respond_to?(:to_param)}).find(#{id}) (#{t1.elapsed_ms})"
82
- rescue => error
83
- Quandl::Logger.error "Quandl::Cassinatra::Dataset.find #{error}"
84
- end
85
- result = self.class.parent.new(id: id) if result.nil?
86
- result
87
- }
88
-
89
- end
90
-
91
- end
92
-
93
- end
94
- end
95
- end
96
- end
@@ -1,13 +0,0 @@
1
- module Quandl
2
- module Cassinatra
3
- module Model
4
-
5
- class DatasetAttribute
6
-
7
- include Concerns::Properties
8
-
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,36 +0,0 @@
1
- module Quandl
2
- module Cassinatra
3
- module Model
4
-
5
- class Multiset
6
-
7
- include Model::Dataset::Searchable
8
- include Concerns::Properties
9
-
10
-
11
- search_helper :to_dataset, -> { dataset }
12
- search_helper :dataset, -> { find('multiset') }
13
-
14
- search_scope :columns, ->(v){ where( columns: v ) }
15
-
16
- attributes :id, :column_ids, :data
17
-
18
- delegate :columns_count, :created_at, :frequency, :rows_count, :type, :updated_at, to: :dataset_attribute
19
-
20
- def data_table
21
- Data::Table.new( self.data || [] )
22
- end
23
- def dataset_attribute(*args)
24
- return @dataset_attribute if @dataset_attribute
25
- # options
26
- options = args.extract_options!
27
- count = options[:count] == true
28
- # grab dataset_attribute
29
- @dataset_attribute = DatasetAttribute.where( count: count ).find(id)
30
- end
31
-
32
- end
33
-
34
- end
35
- end
36
- end
@@ -1,30 +0,0 @@
1
- require 'yajl'
2
-
3
- module Her
4
- module Model
5
- # remove deprecated data method since cassinatra returns data: []
6
- module DeprecatedMethods
7
- remove_method :data
8
- remove_method :data=
9
- end
10
- end
11
- module Middleware
12
- class ParseJSON < Faraday::Response::Middleware
13
- # @private
14
- def parse_json(body = nil)
15
- body ||= '{}'
16
- message = "Response from the API must behave like a Hash or an Array (last JSON response was #{body.inspect})"
17
-
18
- json = begin
19
- Yajl.load(body, :symbolize_keys => true)
20
- rescue Yajl::ParseError
21
- raise Her::Errors::ParseError, message
22
- end
23
-
24
- raise Her::Errors::ParseError, message unless json.is_a?(Hash) or json.is_a?(Array)
25
-
26
- json
27
- end
28
- end
29
- end
30
- end