cube-no-apes 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
@@ -0,0 +1,53 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ *.un~
15
+
16
+ *.swp
17
+
18
+ # jeweler generated
19
+ pkg
20
+
21
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
22
+ #
23
+ # * Create a file at ~/.gitignore
24
+ # * Include files you want ignored
25
+ # * Run: git config --global core.excludesfile ~/.gitignore
26
+ #
27
+ # After doing this, these files will be ignored in all your git projects,
28
+ # saving you from having to 'pollute' every project you touch with them
29
+ #
30
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
31
+ #
32
+ # For MacOS:
33
+ #
34
+ #.DS_Store
35
+
36
+ # For TextMate
37
+ #*.tmproj
38
+ #tmtags
39
+
40
+ # For emacs:
41
+ #*~
42
+ #\#*
43
+ #.\#*
44
+
45
+ # For vim:
46
+ #*.swp
47
+
48
+ # For redcar:
49
+ #.redcar
50
+
51
+ # For rubinius:
52
+ #*.rbc
53
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem "vcr"
7
+ gem "rspec", "~> 2.8.0"
8
+ gem "bundler", ">= 1.0.0"
9
+ end
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cube (1.4.0)
5
+ savon
6
+ webmock
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ addressable (2.2.6)
12
+ akami (1.0.0)
13
+ gyoku (>= 0.4.0)
14
+ builder (3.0.0)
15
+ crack (0.3.1)
16
+ diff-lcs (1.1.3)
17
+ gyoku (0.4.4)
18
+ builder (>= 2.1.2)
19
+ httpi (0.9.5)
20
+ rack
21
+ nokogiri (1.5.0)
22
+ nori (1.0.2)
23
+ rack (1.4.1)
24
+ rspec (2.8.0)
25
+ rspec-core (~> 2.8.0)
26
+ rspec-expectations (~> 2.8.0)
27
+ rspec-mocks (~> 2.8.0)
28
+ rspec-core (2.8.0)
29
+ rspec-expectations (2.8.0)
30
+ diff-lcs (~> 1.1.2)
31
+ rspec-mocks (2.8.0)
32
+ savon (0.9.7)
33
+ akami (~> 1.0)
34
+ builder (>= 2.1.2)
35
+ gyoku (>= 0.4.0)
36
+ httpi (~> 0.9)
37
+ nokogiri (>= 1.4.0)
38
+ nori (~> 1.0)
39
+ wasabi (~> 2.0)
40
+ vcr (1.11.3)
41
+ wasabi (2.0.0)
42
+ nokogiri (>= 1.4.0)
43
+ webmock (1.7.10)
44
+ addressable (~> 2.2, > 2.2.5)
45
+ crack (>= 0.1.7)
46
+
47
+ PLATFORMS
48
+ java
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler (>= 1.0.0)
53
+ cube!
54
+ rspec (~> 2.8.0)
55
+ vcr
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 drKreso
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ Cube
2
+ ================
3
+
4
+ Talk to the OLAP based backend via XMLA SOAP messages from Ruby.
5
+ You can send (simple) MDX queries and get the result back in a human friendly from.
6
+
7
+ Installation
8
+ ------------
9
+ Add to Gemfile
10
+
11
+ ```
12
+ gem 'cube'
13
+ ```
14
+
15
+ Configuration
16
+ --------------
17
+ Set up your catalog and endpoint
18
+
19
+ ```
20
+ XMLA.configure do |c|
21
+ c.catalog = "OUTAGE"
22
+ c.endpoint = "http://localhost:8383/mondrian/xmla"
23
+ end
24
+ ```
25
+
26
+ Querying the OLAP
27
+ -------
28
+ ```
29
+ table = XMLA::Cube.execute <<-MDX
30
+ SELECT [Location].[City].children on COLUMNS,
31
+ [Measures].[Count] on ROWS
32
+ FROM [OUTAGE]"
33
+ MDX
34
+ ```
35
+ Table has two attributes: header and rows.
36
+
37
+ Scalar results
38
+ -----------
39
+ ```
40
+ average_mtbf = XMLA::Cube.execute_scalar <<-MDX
41
+ SELECT {Hierarchize({[Measures].[MTBF]})} ON COLUMNS
42
+ FROM [OUTAGE]
43
+ WHERE [Country].[Croatia]
44
+ MDX
45
+ ```
46
+
47
+ Limitations
48
+ ------------
49
+ * No drill down (fails to even parse the result)
50
+ * No multi named columns
51
+ * Tested only with icCube and Mondrian XMLA, in theory works with every XMLA provider
52
+
53
+ Contributing to cube
54
+ -------------------------------
55
+
56
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
57
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
58
+ * Fork the project
59
+ * Start a feature/bugfix branch
60
+ * Commit and push until you are happy with your contribution
61
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
62
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
63
+
64
+ Copyright
65
+ ----------
66
+
67
+ Copyright (c) 2012 drKreso. See LICENSE.txt for
68
+ further details.
69
+
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ $:.push File.expand_path("../lib", __FILE__)
7
+ require "cube/version"
8
+
9
+ begin
10
+ Bundler::GemHelper.install_tasks
11
+ rescue Bundler::BundlerError => e
12
+ $stderr.puts e.message
13
+ $stderr.puts "Run `bundle install` to install missing gems"
14
+ exit e.status_code
15
+ end
16
+
17
+ require 'rspec/core'
18
+ require 'rspec/core/rake_task'
19
+ RSpec::Core::RakeTask.new(:spec) do |spec|
20
+ spec.pattern = FileList['spec/**/*_spec.rb']
21
+ end
22
+
23
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
24
+ spec.pattern = 'spec/**/*_spec.rb'
25
+ spec.rcov = true
26
+ end
27
+
28
+ task :default => :spec
29
+
30
+ require 'rake/rdoctask'
31
+ Rake::RDocTask.new do |rdoc|
32
+ version = Cube::VERSION
33
+
34
+ rdoc.rdoc_dir = 'rdoc'
35
+ rdoc.title = "cube #{version}"
36
+ rdoc.rdoc_files.include('README*')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "cube/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["drKreso", "stellard"]
8
+ gem.email = ["kresimir.bojcic@gmail.com", "scott@kujilabs.com"]
9
+ gem.description = "Eases the pain I had to go through to get to the data out of XMLA based OLAP provider(Mondiran, Pentaho, icCube)"
10
+ gem.summary = "Get's the data from OLAP cube via XMLA(Mondiran, Pentaho, icCube)"
11
+ gem.homepage = "http://github.com/kujilabs/cube"
12
+ gem.date = "2012-05-13"
13
+
14
+
15
+ gem.licenses = ["MIT"]
16
+ gem.files = `git ls-files`.split($\)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.name = "cube-no-apes"
20
+ gem.require_paths = ["lib"]
21
+ gem.version = Cube::VERSION
22
+
23
+
24
+ gem.add_dependency "savon", ">= 0"
25
+ gem.add_dependency "webmock", ">= 0"
26
+
27
+ end
28
+
@@ -0,0 +1,2 @@
1
+ require_relative 'cube/xmla.rb'
2
+ require_relative 'cube/cube.rb'
@@ -0,0 +1,149 @@
1
+ require 'savon'
2
+ require 'bigdecimal'
3
+ require_relative 'olap_result'
4
+
5
+ Savon.configure do |config|
6
+ config.soap_version = 1
7
+ config.log = false
8
+ end
9
+
10
+ HTTPI.log = false
11
+
12
+ module XMLA
13
+
14
+ class Cube
15
+ attr_reader :query, :catalog
16
+
17
+ def Cube.execute(query, catalog = XMLA.catalog)
18
+ OlapResult.new(Cube.new(query, catalog).as_table)
19
+ end
20
+
21
+ def Cube.execute_scalar(query, catalog = XMLA.catalog)
22
+ BigDecimal.new Cube.new(query, catalog).as_table[0]
23
+ end
24
+
25
+ def as_table
26
+ return [table] if y_size == 0
27
+ clean_table(table, y_size).reduce([]) { |result, row| result << row.flatten }
28
+ end
29
+
30
+ private
31
+
32
+ #header and rows
33
+ def table
34
+ if (header.size == 1 && y_size == 0)
35
+ cell_data[0]
36
+ else
37
+ (0...y_axe.size).reduce(header) do |result, j|
38
+ result << ( y_axe[j] + (0...x_size).map { |i| "#{cell_data[i + j]}" })
39
+ end
40
+ end
41
+ end
42
+
43
+ def header
44
+ [ ( (0..y_size - 1).reduce([]) { |header| header << '' } << x_axe).flatten ]
45
+ end
46
+
47
+ def axes
48
+ axes = all_axes.select { |axe| axe[:@name] != "SlicerAxis" }
49
+ @axes ||= axes.reduce([]) do |result, axe|
50
+ result << tuple(axe).reduce([]) { |y, member|
51
+ data = (member[0] == :member) ? member[1] : member[:member]
52
+ if ( data.class == Hash || data.size == 1 )
53
+ y << [data[:caption].strip].flatten
54
+ else
55
+ y << data.select { |item_data| item_data.class == Hash }.reduce([]) do |z,item_data|
56
+ z << item_data[:caption].strip
57
+ end
58
+ end
59
+ }
60
+ end
61
+ end
62
+
63
+ def initialize(query, catalog)
64
+ @query = query
65
+ @catalog = catalog
66
+ @response = get_response
67
+ self
68
+ end
69
+
70
+ def get_response
71
+ client = Savon::Client.new do
72
+ wsdl.document = File.expand_path("../../wsdl/xmla.xml", __FILE__)
73
+ wsdl.endpoint = XMLA.endpoint
74
+ end
75
+
76
+ @response = client.request :execute, xmlns:"urn:schemas-microsoft-com:xml-analysis" do
77
+ soap.body = Cube.request_body(query, catalog)
78
+ end
79
+ end
80
+
81
+ #cleanup table so items don't repeat (if they are same)
82
+ def clean_table(table, number_of_colums)
83
+ above_row = []
84
+ #filter if they are not last column, and they are same as the item on the row above
85
+ table.reduce([]) { |result, row|
86
+ result << row.each_with_index.map do |item,i|
87
+ if i == number_of_colums
88
+ item
89
+ else
90
+ item == above_row[i] ? '' : item
91
+ end
92
+ end
93
+ above_row = row
94
+ result
95
+ }
96
+ end
97
+
98
+ def cell_data
99
+ cell_data = @response.to_hash[:execute_response][:return][:root][:cell_data]
100
+ return [""] if cell_data.nil?
101
+ @data ||= cell_data.reduce([]) do |data, cell|
102
+ cell[1].reduce(data) do |data, value|
103
+ data << (value.class == Hash ? value[:value] : value[1] )
104
+ end
105
+ end
106
+ end
107
+
108
+ def tuple axe
109
+ axe[:tuples].nil? ? [] : axe[:tuples][:tuple]
110
+ end
111
+
112
+ def all_axes
113
+ @response.to_hash[:execute_response][:return][:root][:axes][:axis]
114
+ end
115
+
116
+ def x_axe
117
+ @x_axe ||= axes[0]
118
+ end
119
+
120
+ def y_axe
121
+ @y_axe ||= axes[1]
122
+ end
123
+
124
+ def y_size
125
+ (y_axe.nil? || y_axe[0].nil?) ? 0 : y_axe[0].size
126
+ end
127
+
128
+ def x_size
129
+ x_axe.size
130
+ end
131
+
132
+ def Cube.request_body(query, catalog)
133
+ <<-REQUEST
134
+ <Command>
135
+ <Statement> <![CDATA[ #{query} ]]> </Statement>
136
+ </Command>
137
+ <Properties>
138
+ <PropertyList>
139
+ <Catalog>#{catalog}</Catalog>
140
+ <Format>Multidimensional</Format>
141
+ <AxisFormat>TupleFormat</AxisFormat>
142
+ </PropertyList>
143
+ </Properties>
144
+ REQUEST
145
+ end
146
+ end
147
+ end
148
+
149
+
@@ -0,0 +1,13 @@
1
+ class OlapResult
2
+ attr_reader :header, :rows
3
+ def initialize(table)
4
+ @header = table[0]
5
+ table.delete_at(0)
6
+ @rows = table
7
+ end
8
+
9
+ def prepare_data
10
+ result = [] << [@header] << @rows
11
+ result.flatten(1)
12
+ end
13
+ end