olap-xmla 0.0.1 → 0.0.2
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/.gitignore +1 -0
- data/Gemfile +1 -0
- data/README.md +79 -2
- data/lib/olap/xmla.rb +42 -2
- data/lib/olap/xmla/client.rb +74 -0
- data/lib/olap/xmla/response.rb +154 -0
- data/lib/olap/xmla/version.rb +1 -1
- data/olap-xmla.gemspec +4 -1
- data/spec/gem_spec.rb +72 -0
- data/spec/spec_helper.rb +11 -0
- metadata +51 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 353d1787b60fcbfdb612748987277c3d3b4046ea
|
4
|
+
data.tar.gz: b7e723cf2067e094e4ba74e51267b3b3c2cd2048
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9558ccbf3c6d913a7074ea34b6bb722bc5b75983e0dff1890ce98bbd45f2f1d000ada9ce790493988d8da66993439ff8dedd8062425d07f1e295954e0312a896
|
7
|
+
data.tar.gz: ddafa507a59edd7a7cab7035c5389672d9b156594b0550726b5ef36894710500407eb93757b536d42590a128ede68a018668a4383ac605263af5f36bb6988c5d
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Olap::Xmla
|
2
2
|
|
3
|
-
|
3
|
+
The gem connects to OLAP database using XMLA interface and executes MDX queries.
|
4
|
+
|
5
|
+
Can be used in Ruby or Rails applications to display and analyse data from OLAP databases.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -20,7 +22,82 @@ Or install it yourself as:
|
|
20
22
|
|
21
23
|
## Usage
|
22
24
|
|
23
|
-
|
25
|
+
Using the gem is very simple, only basic knowledge on OLAP is required.
|
26
|
+
|
27
|
+
### Connecting to server
|
28
|
+
|
29
|
+
To use the gem, you need to know the connection requisites to connect to XMLA server:
|
30
|
+
|
31
|
+
1. Server URL ( typically, http: or https: URL )
|
32
|
+
2. Datasource and catalog names. You can check them in your XMLA server configuration
|
33
|
+
|
34
|
+
Connecting to the server and executing MDX are straightforward:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require 'olap/xmla'
|
38
|
+
|
39
|
+
client = Olap::Xmla.client({
|
40
|
+
server: 'http://your-olap-server',
|
41
|
+
datasource: 'your-datasource',
|
42
|
+
catalog: 'your-catalog'})
|
43
|
+
response = client.request 'your-mdx-here'
|
44
|
+
```
|
45
|
+
|
46
|
+
### Configuration in Rails
|
47
|
+
|
48
|
+
If you are using this gem in Rails application, which uses just single OLAP data source,
|
49
|
+
you can simplify the code by pre-configuring the XMLA connection.
|
50
|
+
|
51
|
+
Create a file olap.rb in config/initializers directory with the following content:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
Olap::Xmla.default_options= { server: 'http://your-olap-server',
|
55
|
+
datasource: 'your-datasource',
|
56
|
+
catalog: 'your-catalog'}
|
57
|
+
```
|
58
|
+
|
59
|
+
Then in Rails application code you can simply do:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
response = Olap::Xmla.client.request 'your-mdx-here'
|
63
|
+
```
|
64
|
+
|
65
|
+
### Querying MDX
|
66
|
+
|
67
|
+
The gem does not parse MDX, just passes it to XMLA server.
|
68
|
+
|
69
|
+
However, it can do substituting parameters in the query:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
MDX_QUERY = 'SET [~ROWS_Date] AS {[DateTime].[Date].[Date].[%DATE%]}'
|
73
|
+
|
74
|
+
Olap::Xmla.client.request MDX_QUERY, {'%DATE%' => '20150530'}
|
75
|
+
```
|
76
|
+
|
77
|
+
This allows to store MDX queries in constants, while execute them with dynamic parameters.
|
78
|
+
Note, that you should never use these parameters directly from Rails request, as
|
79
|
+
this may create security breach!
|
80
|
+
|
81
|
+
### Using response on Query
|
82
|
+
|
83
|
+
|
84
|
+
You may use the response to render the results to user, or post-process it to analyse the data
|
85
|
+
The following methods can be used to request the meta-data and data from the response:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
response = client.request(mdx)
|
89
|
+
|
90
|
+
|
91
|
+
# Meta - data of the response
|
92
|
+
response.measures # array of the columns definitions ( :name / :caption )
|
93
|
+
response.dimensions # array of the rows definitions ( :name )
|
94
|
+
|
95
|
+
# Response data
|
96
|
+
response.rows # rows of the response
|
97
|
+
response.to_hash # response as a hash
|
98
|
+
response.column_values(column_num) # just one column of the response
|
99
|
+
|
100
|
+
```
|
24
101
|
|
25
102
|
## Contributing
|
26
103
|
|
data/lib/olap/xmla.rb
CHANGED
@@ -1,10 +1,50 @@
|
|
1
1
|
require "olap/xmla/version"
|
2
|
+
require "olap/xmla/client"
|
2
3
|
|
3
4
|
module Olap
|
5
|
+
|
6
|
+
#
|
7
|
+
# Connects to XMLA[https://en.wikipedia.org/wiki/XML_for_Analysis] server and executes MDX[https://en.wikipedia.org/wiki/MultiDimensional_eXpressions] queries
|
8
|
+
#
|
4
9
|
module Xmla
|
5
10
|
|
6
|
-
|
7
|
-
|
11
|
+
@@connect_options = {}
|
12
|
+
|
13
|
+
# Configure the default options to connect to XMLA server
|
14
|
+
# Can be optionally used to setup connection options in one place in application,
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
# >> Olap::Xmla.default_options = {server: 'http://your-olap-server', datasource: 'your-datasource', catalog: 'your-catalog'}
|
18
|
+
# >> Olap::Xmla.client.request mdx
|
19
|
+
# => #<Olap::Xmla::Response:0x000001035b9510 @response={ ...
|
20
|
+
#
|
21
|
+
# Look client connect_options for the list of options to be specified
|
22
|
+
#
|
23
|
+
def self.default_options= options
|
24
|
+
@@connect_options = options
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a client, which can be used then to execute MDX queries
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# >> client = Olap::Xmla.client(server: 'http://your-olap-server', datasource: 'your-datasource', catalog: 'your-catalog')
|
31
|
+
# >> response = client.request mdx
|
32
|
+
# => #<Olap::Xmla::Response:0x000001035b9510 @response={ ...
|
33
|
+
#
|
34
|
+
# ==== connect_options
|
35
|
+
#
|
36
|
+
# * +:server+ - URL to connect to XMLA server (required)
|
37
|
+
# * +:datasource+ - the name of datasource (required)
|
38
|
+
# * +:catalog+ - the name of catalog (required)
|
39
|
+
# * +:open_timeout+ - open timeout to connect to XMLA server, optional, default is 60 sec
|
40
|
+
# * +:read_timeout+ - open timeout to read data from XMLA server, optional, default is 300 sec
|
41
|
+
#
|
42
|
+
#
|
43
|
+
def self.client connect_options = {}
|
44
|
+
options = @@connect_options.merge connect_options
|
45
|
+
raise "Connect options must define :server, :datasource and :catalog options" unless
|
46
|
+
options[:server] && options[:datasource] && options[:catalog]
|
47
|
+
Olap::Xmla::Client.new options[:server], options[:datasource], options[:catalog], options
|
8
48
|
end
|
9
49
|
|
10
50
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'olap/xmla/response'
|
3
|
+
|
4
|
+
class Olap::Xmla::Client
|
5
|
+
|
6
|
+
attr_reader :data_source, :catalog, :client
|
7
|
+
|
8
|
+
def initialize server, data_source, catalog, options
|
9
|
+
|
10
|
+
@catalog = catalog
|
11
|
+
@data_source = data_source
|
12
|
+
@client = Savon.client do
|
13
|
+
endpoint server
|
14
|
+
namespace "urn:schemas-microsoft-com:xml-analysis"
|
15
|
+
open_timeout (options[:open_timeout] || 60)
|
16
|
+
read_timeout (options[:read_timeout] || 300)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Executes multiple MDX queries as a batch
|
21
|
+
#
|
22
|
+
# Arguments:
|
23
|
+
# * +mdx_requests+ - Collection of MDX requests
|
24
|
+
# * +parameters+ - Map of parameters to substitute in MDX request, optional
|
25
|
+
#
|
26
|
+
def batch mdx_requests, parameters = {}
|
27
|
+
mdx_requests.collect{|mdx|
|
28
|
+
request mdx, parameters
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Execute MDX queries, substituting parameters in the query
|
33
|
+
#
|
34
|
+
# Arguments:
|
35
|
+
# * +mdx_request+ - MDX request as a string, required
|
36
|
+
# * +parameters+ - Map of parameters to substitute in MDX request, optional
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# client.request 'SET [~ROWS_Date] AS {[DateTime].[Date].[Date].[%DATE%]}', {'%DATE%' => '20150530'}
|
41
|
+
# will execute actual MDX: SET [~ROWS_Date] AS {[DateTime].[Date].[Date].[20150530]}
|
42
|
+
#
|
43
|
+
#
|
44
|
+
def request mdx_request, parameters = {}
|
45
|
+
|
46
|
+
mdx = mdx_request.clone
|
47
|
+
|
48
|
+
parameters.each{|k,v|
|
49
|
+
mdx.gsub!(k,v)
|
50
|
+
}
|
51
|
+
|
52
|
+
ops = client.operation('Execute')
|
53
|
+
p = { 'wsdl:PropertyList' => {'wsdl:DataSourceInfo' => data_source,
|
54
|
+
'wsdl:Catalog' => catalog,
|
55
|
+
'wsdl:Format' => 'Multidimensional',
|
56
|
+
'wsdl:AxisFormat'=> 'TupleFormat'} }
|
57
|
+
|
58
|
+
|
59
|
+
r = ops.call( message: {'wsdl:Command' => { 'wsdl:Statement' => mdx}, 'wsdl:Properties' => p })
|
60
|
+
|
61
|
+
unless r.success?
|
62
|
+
raise "Error executing #{mdx} in #{catalog} #{data_source}: #{r.http_error} #{r.soap_fault}"
|
63
|
+
end
|
64
|
+
|
65
|
+
Olap::Xmla::Response.new r.body[:execute_response][:return][:root]
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
@@ -0,0 +1,154 @@
|
|
1
|
+
class Olap::Xmla::Response
|
2
|
+
|
3
|
+
attr_reader :response
|
4
|
+
|
5
|
+
def initialize response
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns true if the response has any data
|
10
|
+
def has_data?
|
11
|
+
not response[:cell_data][:cell].empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
# Collection of measures in response
|
15
|
+
#
|
16
|
+
# * +:name+ the name of measure
|
17
|
+
# * +:caption+ display name of measure
|
18
|
+
#
|
19
|
+
def measures
|
20
|
+
response[:axes][:axis][0][:tuples][:tuple].collect{|m|
|
21
|
+
{
|
22
|
+
name: m[:member][:u_name],
|
23
|
+
caption: m[:member][:caption]
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Collection of dimensions in response
|
29
|
+
#
|
30
|
+
# * +:name+ the name of dimension
|
31
|
+
#
|
32
|
+
def dimensions
|
33
|
+
response[:olap_info][:axes_info][:axis_info][1][:hierarchy_info].collect{|m|
|
34
|
+
{
|
35
|
+
name: m[:@name]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Collection of result rows
|
42
|
+
# * rownum number of row ( 1... N)
|
43
|
+
# * labels - array of tuples per the row
|
44
|
+
# value - the value of tuple
|
45
|
+
# name - the name of tuple
|
46
|
+
# * values - the values array
|
47
|
+
# measure - metric name
|
48
|
+
# value - metric value
|
49
|
+
# fmt_value - formatted metric value
|
50
|
+
# colnum - column number ( 1..N)
|
51
|
+
def rows
|
52
|
+
|
53
|
+
return [] unless response[:cell_data]
|
54
|
+
|
55
|
+
measures = [response[:axes][:axis][0][:tuples][:tuple]].flatten
|
56
|
+
cells = [response[:cell_data][:cell]].flatten
|
57
|
+
|
58
|
+
cell_ordinal = 0
|
59
|
+
cell_index = 0
|
60
|
+
rownum = 0
|
61
|
+
|
62
|
+
[response[:axes][:axis][1][:tuples][:tuple]].flatten.collect{ |tuple|
|
63
|
+
rownum += 1
|
64
|
+
colnum = 0
|
65
|
+
tuple_member = [tuple[:member]].flatten
|
66
|
+
{ rownum: rownum,
|
67
|
+
labels: tuple_member.collect{|member|
|
68
|
+
value = member[:caption]
|
69
|
+
value = nil if value=='#null'
|
70
|
+
{value: value, name: member[:@hierarchy]}
|
71
|
+
},
|
72
|
+
values: measures.collect{|m|
|
73
|
+
|
74
|
+
colnum += 1
|
75
|
+
|
76
|
+
if (cell=cells[cell_index]) && cell[:@cell_ordinal].to_i==cell_ordinal
|
77
|
+
cell_index += 1
|
78
|
+
cell_ordinal += 1
|
79
|
+
{ colnum: colnum, measure: m[:member][:u_name], value: cell[:value], fmt_value: cell[:fmt_value]}
|
80
|
+
else
|
81
|
+
cell_ordinal += 1
|
82
|
+
{ colnum: colnum, measure: m[:member][:u_name], value: nil, fmt_value: nil}
|
83
|
+
end
|
84
|
+
|
85
|
+
}
|
86
|
+
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
# query a colum of the result
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
#
|
96
|
+
# >> response.column_values 1
|
97
|
+
# => [30.0, 1025.0, 884.0, 543.0,...
|
98
|
+
#
|
99
|
+
def column_values column_num
|
100
|
+
|
101
|
+
rows.collect{|row|
|
102
|
+
row[:values].detect{|value|
|
103
|
+
value[:colnum]==column_num
|
104
|
+
}[:value].to_f
|
105
|
+
}
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
# Aggregate result by one of the columns
|
110
|
+
def column_values_aggregate dimension_aggr_index = 0
|
111
|
+
|
112
|
+
result = []
|
113
|
+
index = {}
|
114
|
+
|
115
|
+
rows.each{|row|
|
116
|
+
label = row[:labels][dimension_aggr_index]
|
117
|
+
|
118
|
+
if i = index[label]
|
119
|
+
for j in 0..result[i][:values].count-1
|
120
|
+
result[i][:values][j] += row[:values][j][:value].to_f
|
121
|
+
end
|
122
|
+
else
|
123
|
+
index[label] = result.count
|
124
|
+
result << {
|
125
|
+
rownum: result.count + 1,
|
126
|
+
label: label,
|
127
|
+
values: row[:values].collect{|v| v[:value].to_f }
|
128
|
+
}
|
129
|
+
end
|
130
|
+
}
|
131
|
+
|
132
|
+
result
|
133
|
+
end
|
134
|
+
|
135
|
+
# Convert the response to hash
|
136
|
+
# keys of hash are values of tuples
|
137
|
+
# values of hash are values of metrics
|
138
|
+
#
|
139
|
+
# Example:
|
140
|
+
#
|
141
|
+
# response.to_hash
|
142
|
+
# => {["2014", "05/11/2014"]=>[30.0, 27.0, 0.0], ["2014", "06/11/2014"]=>[1025.0, 688.0, 73.0]
|
143
|
+
#
|
144
|
+
def to_hash
|
145
|
+
Hash[rows.collect{|row|
|
146
|
+
[
|
147
|
+
row[:labels].collect{|l| l[:value].nil? ? nil : l[:value] },
|
148
|
+
row[:values].collect{|l| (l.nil? || l[:value].nil?) ? 0.0 : l[:value].to_f },
|
149
|
+
]
|
150
|
+
|
151
|
+
}]
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
data/lib/olap/xmla/version.rb
CHANGED
data/olap-xmla.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["aleksey@wondersoft.ru"]
|
11
11
|
spec.summary = %q{Pure Ruby gem to make MDX queries on OLAP databases using XMLA connection}
|
12
12
|
spec.description = %q{Can be used with any XMLA-compliant server, like Olaper or Mondrian.}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/Wondersoft/olap-xmla"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -20,4 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", '~> 0'
|
24
|
+
spec.add_runtime_dependency 'savon', '~> 2.8'
|
25
|
+
spec.add_runtime_dependency 'rubyntlm', '~> 0.3.2'
|
23
26
|
end
|
data/spec/gem_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
connection_config = YAML.load File.read 'spec/.config.yaml'
|
5
|
+
|
6
|
+
describe 'Test MDX queries' do
|
7
|
+
|
8
|
+
it 'should request mdx' do
|
9
|
+
|
10
|
+
client = Olap::Xmla.client connection_config
|
11
|
+
|
12
|
+
mdx= "WITH SET [~ROWS_YearByDay] AS " +
|
13
|
+
"{[DateTime].[YearByDay].[Year].Members} " +
|
14
|
+
"SET [~ROWS_Date] AS " +
|
15
|
+
" {[DateTime].[Date].[Date].Members} " +
|
16
|
+
"SELECT " +
|
17
|
+
"NON EMPTY {[Measures].[Slots], [Measures].[Clicks], [Measures].[Conversions]} ON COLUMNS, " +
|
18
|
+
"NON EMPTY NonEmptyCrossJoin([~ROWS_YearByDay], [~ROWS_Date]) ON ROWS " +
|
19
|
+
"FROM [Ad Serving]"
|
20
|
+
|
21
|
+
response = client.request mdx
|
22
|
+
|
23
|
+
expect(response.has_data?).to be true
|
24
|
+
|
25
|
+
expect(response.measures.count).to eq 3
|
26
|
+
expect(response.measures[0][:name]).to eq '[Measures].[Slots]'
|
27
|
+
expect(response.measures[1][:name]).to eq '[Measures].[Clicks]'
|
28
|
+
|
29
|
+
expect(response.dimensions.count).to eq 2
|
30
|
+
|
31
|
+
expect(response.dimensions[0][:name]).to eq 'YearByDay'
|
32
|
+
expect(response.dimensions[1][:name]).to eq 'Date'
|
33
|
+
|
34
|
+
expect(response.rows.count).to be > 100
|
35
|
+
|
36
|
+
expect(response.rows[0][:rownum]).to eq 1
|
37
|
+
|
38
|
+
expect(response.rows[0][:labels].size).to eq 2
|
39
|
+
expect(response.rows[0][:labels][0][:name]).to eq 'YearByDay'
|
40
|
+
expect(response.rows[0][:labels][1][:name]).to eq 'Date'
|
41
|
+
|
42
|
+
expect(response.rows[0][:values].size).to eq 3
|
43
|
+
|
44
|
+
expect(response.rows[0][:values][0][:colnum]).to eq 1
|
45
|
+
expect(response.rows[0][:values][0][:measure]).to eq '[Measures].[Slots]'
|
46
|
+
expect(response.rows[0][:values][0][:value]).to_not be_nil
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should use default connect' do
|
51
|
+
|
52
|
+
Olap::Xmla.default_options = connection_config
|
53
|
+
|
54
|
+
client = Olap::Xmla.client
|
55
|
+
|
56
|
+
mdx= "WITH SET [~ROWS_YearByDay] AS " +
|
57
|
+
"{[DateTime].[YearByDay].[Year].Members} " +
|
58
|
+
"SET [~ROWS_Date] AS " +
|
59
|
+
" {[DateTime].[Date].[Date].Members} " +
|
60
|
+
"SELECT " +
|
61
|
+
"NON EMPTY {[Measures].[Slots], [Measures].[Clicks], [Measures].[Conversions]} ON COLUMNS, " +
|
62
|
+
"NON EMPTY NonEmptyCrossJoin([~ROWS_YearByDay], [~ROWS_Date]) ON ROWS " +
|
63
|
+
"FROM [Ad Serving]"
|
64
|
+
|
65
|
+
response = client.request mdx
|
66
|
+
|
67
|
+
expect(response.has_data?).to be true
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: olap-xmla
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- studnev
|
@@ -38,6 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: savon
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubyntlm
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.3.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.3.2
|
41
83
|
description: Can be used with any XMLA-compliant server, like Olaper or Mondrian.
|
42
84
|
email:
|
43
85
|
- aleksey@wondersoft.ru
|
@@ -51,9 +93,13 @@ files:
|
|
51
93
|
- README.md
|
52
94
|
- Rakefile
|
53
95
|
- lib/olap/xmla.rb
|
96
|
+
- lib/olap/xmla/client.rb
|
97
|
+
- lib/olap/xmla/response.rb
|
54
98
|
- lib/olap/xmla/version.rb
|
55
99
|
- olap-xmla.gemspec
|
56
|
-
|
100
|
+
- spec/gem_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
homepage: https://github.com/Wondersoft/olap-xmla
|
57
103
|
licenses:
|
58
104
|
- MIT
|
59
105
|
metadata: {}
|
@@ -77,4 +123,6 @@ rubygems_version: 2.2.2
|
|
77
123
|
signing_key:
|
78
124
|
specification_version: 4
|
79
125
|
summary: Pure Ruby gem to make MDX queries on OLAP databases using XMLA connection
|
80
|
-
test_files:
|
126
|
+
test_files:
|
127
|
+
- spec/gem_spec.rb
|
128
|
+
- spec/spec_helper.rb
|