rubiks 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in rubiks.gemspec
4
4
  gemspec
5
-
6
- gem 'yajl-ruby'
7
- gem 'redis'
@@ -0,0 +1 @@
1
+ rvm use jruby-1.7.0
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rubiks', :path => '../../'
4
+
5
+ gem 'activerecord', :require => 'active_record'
6
+ gem 'activerecord-jdbcpostgresql-adapter'
7
+ gem 'awesome_print'
8
+ gem 'jruby-openssl'
9
+ gem 'mondrian-olap'
10
+ gem 'pry'
11
+ gem 'pry-nav'
@@ -0,0 +1,14 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+ require 'pry'
4
+
5
+ ActiveRecord::Base.establish_connection(YAML.load_file('./database.yml'))
6
+ require './domain'
7
+
8
+ query = "SELECT {[Measures].[Balance]} ON COLUMNS, {[Customers].children} ON ROWS FROM [CubeAccountSnapshots] WHERE ([Date].[2012].[4])"
9
+
10
+ cas = CubeAccountSnapshot.last
11
+
12
+ binding.pry
13
+
14
+ cas.mdx query
@@ -0,0 +1,5 @@
1
+ adapter: postgresql
2
+ encoding: utf8
3
+ host: localhost
4
+ username: postgres
5
+ database: finance_development
@@ -0,0 +1,44 @@
1
+ module Dimensions
2
+ class Account < ActiveRecord::Base
3
+ include Rubiks::Dimension
4
+
5
+ hierarchy 'Asset/Liability' do
6
+ level :asset_liability
7
+ level :account_type
8
+ end
9
+
10
+ hierarchy 'Institution' do
11
+ level :institution
12
+ end
13
+ end
14
+
15
+ class Customer < ActiveRecord::Base
16
+ include Rubiks::Dimension
17
+
18
+ hierarchy 'Gender' do
19
+ level :gender
20
+ end
21
+ end
22
+
23
+ class Date < ActiveRecord::Base
24
+ include Rubiks::Dimension
25
+
26
+ hierarchy 'Date' do
27
+ level :year
28
+ level :quarter
29
+ level :month
30
+ end
31
+ end
32
+ end
33
+
34
+ module Facts
35
+ class AccountSnapshot < ActiveRecord::Base
36
+ include Rubiks::Fact
37
+
38
+ dimension :account
39
+ dimension :customer
40
+ dimension :date
41
+
42
+ measure :balance
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ # Requires PostgreSQL
3
+ # Setup the finance_development DB
4
+
5
+ require 'bundler'
6
+ Bundler.require
7
+
8
+ config = YAML.load_file('./database.yml')
9
+
10
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres'))
11
+ ActiveRecord::Base.connection.create_database(config['database'])
12
+
13
+ ActiveRecord::Base.establish_connection(config)
14
+
15
+ ActiveRecord::Migration.create_table :accounts do |t|
16
+ t.string :asset_liability
17
+ t.string :account_type
18
+ t.string :institution
19
+ end
20
+
21
+ ActiveRecord::Migration.create_table :dates do |t|
22
+ t.integer :year
23
+ t.integer :quarter
24
+ t.integer :month
25
+ t.integer :day
26
+ end
27
+
28
+ ActiveRecord::Migration.create_table :customers do |t|
29
+ t.string :name
30
+ t.string :gender
31
+ end
32
+
33
+ ActiveRecord::Migration.create_table :account_snapshots do |t|
34
+ t.references :account
35
+ t.references :date
36
+ t.references :customer
37
+ t.decimal :balance
38
+ end
39
+
40
+ require './domain'
41
+
42
+ account = Dimensions::Account.create(:asset_liability => 'ASSET', :account_type => 'Savings', :institution => 'ACU - Awesome Credit Union')
43
+ customer = Dimensions::Customer.create(:name => 'JohnnyT', :gender => 'Male')
44
+ date = Dimesnions::Date.create(:year => 2012, :quarter => 4, :month => 11, :day => 31)
45
+
46
+ Facts::AccountSnapshot.create(:account => account, :customer => customer, :date => date, :balance => 100.00)
data/lib/rubiks/cube.rb CHANGED
@@ -1,9 +1,95 @@
1
1
  module Rubiks
2
- class Cube
3
- def dimensions
2
+ module Cube
3
+ def self.included(klass)
4
+ klass.extend Rubiks::Cube::ClassMethods
4
5
  end
5
6
 
6
- def measures
7
+ module ClassMethods
8
+ def dimension(name)
9
+ model_name = name.to_s
10
+ dimensions << model_name
11
+ belongs_to model_name, :class_name => "Dimensions::#{model_name.classify}"
12
+ end
13
+
14
+ def dimensions
15
+ @dimensions ||= []
16
+ end
17
+
18
+ def measure(name)
19
+ measures << name
20
+ end
21
+
22
+ def measures
23
+ @measures ||= []
24
+ end
25
+ end
26
+
27
+ def mdx(query)
28
+ res = olap.execute(query)
29
+ output = []
30
+ output << res.column_full_names
31
+ res.values.each{ |v| output << v }
32
+ output.join("\n")
33
+ end
34
+
35
+ def to_s
36
+ "#<#{self.class.name}>"
37
+ end
38
+
39
+ def inspect
40
+ "#<#{self.class.name} dims: #{self.class.dimensions.inspect}>"
41
+ end
42
+
43
+
44
+ private
45
+
46
+ def olap
47
+ @olap ||= Mondrian::OLAP::Connection.create(mondrian_config)
48
+ end
49
+
50
+ def mondrian_config
51
+ @mondrian_config ||= begin
52
+ ar_config = ActiveRecord::Base.connection.config
53
+
54
+ {
55
+ :driver => ar_config[:adapter],
56
+ :host => ar_config[:host],
57
+ :database => ar_config[:database],
58
+ :username => ar_config[:username],
59
+ :password => ar_config[:password],
60
+ :schema => mondrian_schema
61
+ }
62
+ end
63
+ end
64
+
65
+ def mondrian_schema
66
+ rubiks_cube = self
67
+ @mondrian_schema ||= Mondrian::OLAP::Schema.define do
68
+ cube rubiks_cube.class.name do
69
+ table rubiks_cube.class.table_name
70
+
71
+ rubiks_cube.class.reflections.each do |name, reflection|
72
+ dimension reflection.name.titleize, :foreign_key => reflection.foreign_key do
73
+
74
+ reflection.class_name.constantize.hierarchies.each do |h|
75
+ hierarchy :has_all => true, :primary_key => :id do
76
+ table reflection.table_name
77
+
78
+ h.levels.each do |l|
79
+ level l.to_s.titleize, :column => l
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+
87
+ rubiks_cube.class.measures.each do |m|
88
+ measure m.to_s.titleize, :column => m, :aggregator => 'avg'
89
+ end
90
+ end
91
+ end
7
92
  end
93
+
8
94
  end
9
95
  end
@@ -1,6 +1,23 @@
1
1
  module Rubiks
2
- class Dimension
2
+ module Dimension
3
+ def self.included(klass)
4
+ klass.extend Rubiks::Dimension::ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def hierarchy(name, &block)
9
+ new_hierarchy = Hierarchy.new(name)
10
+ new_hierarchy.instance_eval(&block) if block_given?
11
+ hierarchies << new_hierarchy
12
+ end
13
+
14
+ def hierarchies
15
+ @hierarchies ||= []
16
+ end
17
+ end
18
+
3
19
  def hierarchies
20
+ self.class.hierarchies
4
21
  end
5
22
  end
6
23
  end
@@ -0,0 +1,15 @@
1
+ module Rubiks
2
+ class Hierarchy
3
+ attr_accessor :name
4
+ attr_reader :levels
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @levels = []
9
+ end
10
+
11
+ def level(name)
12
+ levels << name
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,81 @@
1
+ module Rubiks
2
+ module Transformers
3
+ module LookupTransformer
4
+ ##
5
+ # Public instance methods
6
+ #
7
+ # Looks up the member or creates a new member if missing
8
+ # @param[ActiveRecord Class] The class to lookup
9
+ # @param[String] The external natural key (PK)
10
+ # @return[Object] The found or created member
11
+ def lookup_member(klass, natural_key)
12
+ model_name = klass.name.underscore
13
+ cache_key = "rubiks.lookup.#{model_name}.#{natural_key}"
14
+
15
+ if id = cache.read(cache_key)
16
+ klass.find_by_id(id)
17
+
18
+ elsif existing_member = klass.where(:natural_key => natural_key).first
19
+ cache.write(cache_key, existing_member.id)
20
+ existing_member
21
+
22
+ else
23
+ new_member = klass.new
24
+ new_member.natural_key = natural_key
25
+
26
+ new_member.save!
27
+ cache.write(cache_key, new_member.id)
28
+ new_member
29
+ end
30
+ end
31
+
32
+ # Looks up the surrogate key based off a natural key
33
+ # @param[ActiveRecord Class] The class to lookup
34
+ # @param[String] The external natural key (PK)
35
+ # @return[Integer] The surrogate key of the found or created member
36
+ def lookup(klass, natural_key)
37
+ model_name = klass.name.underscore
38
+ cache_key = "rubiks.lookup.#{model_name}.#{natural_key}"
39
+
40
+ if id = cache.read(cache_key)
41
+ id
42
+
43
+ elsif existing_member = klass.where(:natural_key => natural_key).first
44
+ cache.write(cache_key, existing_member.id)
45
+ existing_member.id
46
+
47
+ else
48
+ new_member = klass.new
49
+ new_member.natural_key = natural_key
50
+
51
+ new_member.save!
52
+ cache.write(cache_key, new_member.id)
53
+ new_member.id
54
+ end
55
+ end
56
+
57
+ def lookup_date(input)
58
+ date = if input == :today
59
+ Date.today
60
+ elsif input == :yesterday
61
+ 1.day.ago
62
+ elsif input.kind_of? Integer
63
+ Time.at(input)
64
+ else
65
+ Date.parse(input)
66
+ end
67
+
68
+ date.strftime('%Y%m%d').to_i
69
+ rescue
70
+ -1
71
+ end
72
+
73
+ private
74
+
75
+ def cache
76
+ @cache ||= Rails.cache
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -1,3 +1,3 @@
1
1
  module Rubiks
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/rubiks.rb CHANGED
@@ -3,12 +3,9 @@ require 'rubiks/version'
3
3
  module Rubiks
4
4
  autoload :Cube, 'rubiks/cube'
5
5
  autoload :Dimension, 'rubiks/dimension'
6
+ autoload :Hierarchy, 'rubiks/hierarchy'
6
7
 
7
- module Cubes
8
- # autoload :Base, 'rubiks/cubes/base'
9
- end
10
-
11
- module Dimensions
12
- # autoload :Base, 'rubiks/dimensions/base'
8
+ module Transformers
9
+ autoload :LookupTransformer, 'rubiks/transformers/lookup_transformer'
13
10
  end
14
11
  end
data/rubiks.gemspec CHANGED
@@ -19,11 +19,13 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_dependency 'arel'
21
21
 
22
- gem.add_development_dependency 'rake'
23
- gem.add_development_dependency 'minitest'
24
- gem.add_development_dependency 'rb-fsevent'
22
+ gem.add_development_dependency 'awesome_print'
25
23
  gem.add_development_dependency 'guard'
26
24
  gem.add_development_dependency 'guard-minitest'
25
+ gem.add_development_dependency 'minitest'
26
+ gem.add_development_dependency 'pry'
27
+ gem.add_development_dependency 'rake'
28
+ gem.add_development_dependency 'rb-fsevent'
27
29
  gem.add_development_dependency 'simplecov'
28
30
  gem.add_development_dependency 'simplecov-gem-adapter'
29
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubiks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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: 2012-10-18 00:00:00.000000000 Z
12
+ date: 2012-11-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: arel
@@ -28,7 +28,39 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  - !ruby/object:Gem::Dependency
31
- name: rake
31
+ name: awesome_print
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: guard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: guard-minitest
32
64
  requirement: !ruby/object:Gem::Requirement
33
65
  none: false
34
66
  requirements:
@@ -60,7 +92,7 @@ dependencies:
60
92
  - !ruby/object:Gem::Version
61
93
  version: '0'
62
94
  - !ruby/object:Gem::Dependency
63
- name: rb-fsevent
95
+ name: pry
64
96
  requirement: !ruby/object:Gem::Requirement
65
97
  none: false
66
98
  requirements:
@@ -76,7 +108,7 @@ dependencies:
76
108
  - !ruby/object:Gem::Version
77
109
  version: '0'
78
110
  - !ruby/object:Gem::Dependency
79
- name: guard
111
+ name: rake
80
112
  requirement: !ruby/object:Gem::Requirement
81
113
  none: false
82
114
  requirements:
@@ -92,7 +124,7 @@ dependencies:
92
124
  - !ruby/object:Gem::Version
93
125
  version: '0'
94
126
  - !ruby/object:Gem::Dependency
95
- name: guard-minitest
127
+ name: rb-fsevent
96
128
  requirement: !ruby/object:Gem::Requirement
97
129
  none: false
98
130
  requirements:
@@ -153,9 +185,17 @@ files:
153
185
  - LICENSE.txt
154
186
  - README.md
155
187
  - Rakefile
188
+ - examples/finance/.rvmrc
189
+ - examples/finance/Gemfile
190
+ - examples/finance/app.rb
191
+ - examples/finance/database.yml
192
+ - examples/finance/domain.rb
193
+ - examples/finance/setup
156
194
  - lib/rubiks.rb
157
195
  - lib/rubiks/cube.rb
158
196
  - lib/rubiks/dimension.rb
197
+ - lib/rubiks/hierarchy.rb
198
+ - lib/rubiks/transformers/lookup_transformer.rb
159
199
  - lib/rubiks/version.rb
160
200
  - rubiks.gemspec
161
201
  - test/rubiks/test_cube.rb
@@ -173,18 +213,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
173
213
  - - ! '>='
174
214
  - !ruby/object:Gem::Version
175
215
  version: '0'
176
- segments:
177
- - 0
178
- hash: 3892697901423370992
179
216
  required_rubygems_version: !ruby/object:Gem::Requirement
180
217
  none: false
181
218
  requirements:
182
219
  - - ! '>='
183
220
  - !ruby/object:Gem::Version
184
221
  version: '0'
185
- segments:
186
- - 0
187
- hash: 3892697901423370992
188
222
  requirements: []
189
223
  rubyforge_project:
190
224
  rubygems_version: 1.8.24