rubiks 0.0.3 → 0.0.4
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.
- data/.rspec +4 -0
- data/.travis.yml +6 -0
- data/Gemfile +17 -2
- data/Guardfile +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +9 -4
- data/Rakefile +3 -8
- data/lib/rubiks/nodes/annotated_node.rb +20 -0
- data/lib/rubiks/nodes/cube.rb +77 -0
- data/lib/rubiks/nodes/dimension.rb +54 -0
- data/lib/rubiks/nodes/hierarchy.rb +55 -0
- data/lib/rubiks/nodes/level.rb +29 -0
- data/lib/rubiks/nodes/measure.rb +66 -0
- data/lib/rubiks/nodes/schema.rb +61 -0
- data/lib/rubiks/nodes/validated_node.rb +47 -0
- data/lib/rubiks/version.rb +2 -2
- data/lib/rubiks.rb +6 -8
- data/rubiks.gemspec +5 -13
- data/spec/examples/mondrian_xml_example_spec.rb +91 -0
- data/spec/rubiks/nodes/annotated_node_spec.rb +24 -0
- data/spec/rubiks/nodes/cube_spec.rb +39 -0
- data/spec/rubiks/nodes/dimension_spec.rb +26 -0
- data/spec/rubiks/nodes/hierarchy_spec.rb +27 -0
- data/spec/rubiks/nodes/level_spec.rb +26 -0
- data/spec/rubiks/nodes/measure_spec.rb +31 -0
- data/spec/rubiks/nodes/schema_spec.rb +59 -0
- data/spec/rubiks/nodes/validated_node_spec.rb +49 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/matchers/be_like.rb +24 -0
- data/spec/support/schema_context.rb +46 -0
- metadata +45 -144
- data/.simplecov +0 -6
- data/examples/finance/.rvmrc +0 -1
- data/examples/finance/Gemfile +0 -11
- data/examples/finance/app.rb +0 -14
- data/examples/finance/database.yml +0 -5
- data/examples/finance/domain.rb +0 -44
- data/examples/finance/setup +0 -46
- data/lib/rubiks/cube.rb +0 -95
- data/lib/rubiks/dimension.rb +0 -23
- data/lib/rubiks/hierarchy.rb +0 -15
- data/lib/rubiks/transformers/lookup_transformer.rb +0 -101
- data/test/rubiks/test_cube.rb +0 -15
- data/test/rubiks/test_dimension.rb +0 -11
- data/test/test_helper.rb +0 -6
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,4 +1,19 @@
|
|
1
|
-
source '
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
#
|
3
|
+
# rubiks.gemspec defines the runtime dependencies
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
# Test and development dependencies are defined here
|
7
|
+
# so CI can include just test dependencies
|
8
|
+
group :test do
|
9
|
+
gem 'rake'
|
10
|
+
gem 'rspec'
|
11
|
+
gem 'rspec-pride'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :development do
|
15
|
+
gem 'awesome_print'
|
16
|
+
gem 'pry'
|
17
|
+
gem 'pry-nav'
|
18
|
+
gem 'simplecov'
|
19
|
+
end
|
data/Guardfile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
guard '
|
2
|
-
watch(%r
|
3
|
-
watch(%r
|
4
|
-
watch(
|
1
|
+
guard 'rspec' do
|
2
|
+
watch(%r{^spec/.+_spec\.rb$})
|
3
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
4
|
+
watch('spec/spec_helper.rb') { "spec" }
|
5
5
|
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
# Rubiks
|
2
2
|
|
3
|
-
|
3
|
+
[](http://badge.fury.io/rb/rubiks)
|
4
|
+
[](https://travis-ci.org/moneydesktop/rubiks)
|
5
|
+
[](https://codeclimate.com/github/moneydesktop/rubiks)
|
4
6
|
|
5
|
-
|
7
|
+
Rubiks is a Ruby gem that defines an OLAP schema with `#to_xml` to generate a Mondrian XML schema and `#to_json` for everything else.
|
6
8
|
|
7
|
-
|
9
|
+
## Installation
|
8
10
|
|
9
|
-
|
11
|
+
Run `gem install rubiks` to install the gem on its own.
|
12
|
+
|
13
|
+
Or you can add the following to your Gemfile and run the `bundle` command to install it.
|
10
14
|
|
15
|
+
gem 'rubiks'
|
11
16
|
|
12
17
|
## Contributing
|
13
18
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
require 'rake'
|
3
|
-
require 'rake/testtask'
|
1
|
+
require 'rspec/core/rake_task'
|
4
2
|
|
5
|
-
|
6
|
-
t.pattern = 'test/**/test_*.rb'
|
7
|
-
t.libs.push 'test'
|
8
|
-
end
|
3
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
4
|
|
10
|
-
task :default => :
|
5
|
+
task :default => :spec
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubiks/nodes/validated_node'
|
2
|
+
|
3
|
+
module ::Rubiks
|
4
|
+
class AnnotatedNode < ::Rubiks::ValidatedNode
|
5
|
+
value :name, String
|
6
|
+
|
7
|
+
validates :name_present
|
8
|
+
|
9
|
+
def name_present
|
10
|
+
errors << "Name required on #{self.class.name.split('::').last}" if self.name.blank?
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_name(name_value)
|
14
|
+
return if name_value.nil?
|
15
|
+
|
16
|
+
self.name = name_value.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rubiks/nodes/annotated_node'
|
2
|
+
require 'rubiks/nodes/dimension'
|
3
|
+
require 'rubiks/nodes/measure'
|
4
|
+
|
5
|
+
module ::Rubiks
|
6
|
+
|
7
|
+
class Cube < ::Rubiks::AnnotatedNode
|
8
|
+
child :dimensions, [::Rubiks::Dimension]
|
9
|
+
child :measures, [::Rubiks::Measure]
|
10
|
+
|
11
|
+
validates :dimensions_present, :measures_present
|
12
|
+
|
13
|
+
def self.new_from_hash(hash={})
|
14
|
+
new_instance = new('',[],[])
|
15
|
+
return new_instance.from_hash(hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_hash(working_hash)
|
19
|
+
return self if working_hash.nil?
|
20
|
+
working_hash.stringify_keys!
|
21
|
+
|
22
|
+
parse_name(working_hash.delete('name'))
|
23
|
+
parse_dimensions(working_hash.delete('dimensions'))
|
24
|
+
parse_measures(working_hash.delete('measures'))
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
def measures_present
|
29
|
+
if self.measures.present?
|
30
|
+
self.measures.each do |measure|
|
31
|
+
measure.validate
|
32
|
+
errors.push(*measure.errors)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
errors << 'Measures Required for Cube'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_measures(measures_array)
|
40
|
+
return if measures_array.nil? || measures_array.empty?
|
41
|
+
|
42
|
+
measures_array.each do |measure_hash|
|
43
|
+
self.measures << ::Rubiks::Measure.new_from_hash(measure_hash)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def dimensions_present
|
48
|
+
if self.dimensions.present?
|
49
|
+
self.dimensions.each do |dimension|
|
50
|
+
dimension.validate
|
51
|
+
errors.push(*dimension.errors)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
errors << 'Dimensions Required for Cube'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_dimensions(dimensions_array)
|
59
|
+
return if dimensions_array.nil? || dimensions_array.empty?
|
60
|
+
|
61
|
+
dimensions_array.each do |dimension_hash|
|
62
|
+
self.dimensions << ::Rubiks::Dimension.new_from_hash(dimension_hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_hash
|
67
|
+
hash = {}
|
68
|
+
|
69
|
+
hash['name'] = self.name.to_s if self.name.present?
|
70
|
+
hash['dimensions'] = self.dimensions.map(&:to_hash) if self.dimensions.present?
|
71
|
+
hash['measures'] = self.measures.map(&:to_hash) if self.measures.present?
|
72
|
+
|
73
|
+
return hash
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubiks/nodes/validated_node'
|
2
|
+
require 'rubiks/nodes/hierarchy'
|
3
|
+
|
4
|
+
module ::Rubiks
|
5
|
+
|
6
|
+
class Dimension < ::Rubiks::AnnotatedNode
|
7
|
+
child :hierarchies, [::Rubiks::Hierarchy]
|
8
|
+
|
9
|
+
validates :hierarchies_present
|
10
|
+
|
11
|
+
def self.new_from_hash(hash={})
|
12
|
+
new_instance = new('',[])
|
13
|
+
return new_instance.from_hash(hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def hierarchies_present
|
17
|
+
if self.hierarchies.present?
|
18
|
+
self.hierarchies.each do |hierarchy|
|
19
|
+
hierarchy.validate
|
20
|
+
errors.push(*hierarchy.errors)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
errors << 'Hierarchies Required for Dimension'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def from_hash(working_hash)
|
28
|
+
return self if working_hash.nil?
|
29
|
+
working_hash.stringify_keys!
|
30
|
+
|
31
|
+
parse_name(working_hash.delete('name'))
|
32
|
+
parse_hierarchies(working_hash.delete('hierarchies'))
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_hierarchies(hierarchies_array)
|
37
|
+
return if hierarchies_array.nil? || hierarchies_array.empty?
|
38
|
+
|
39
|
+
hierarchies_array.each do |hierarchy_hash|
|
40
|
+
self.hierarchies << ::Rubiks::Hierarchy.new_from_hash(hierarchy_hash)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
hash = {}
|
46
|
+
|
47
|
+
hash['name'] = self.name.to_s if self.name.present?
|
48
|
+
hash['hierarchies'] = self.hierarchies.map(&:to_hash) if self.hierarchies.present?
|
49
|
+
|
50
|
+
return hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubiks/nodes/annotated_node'
|
2
|
+
require 'rubiks/nodes/level'
|
3
|
+
|
4
|
+
module ::Rubiks
|
5
|
+
|
6
|
+
class Hierarchy < ::Rubiks::AnnotatedNode
|
7
|
+
child :levels, [::Rubiks::Level]
|
8
|
+
|
9
|
+
validates :levels_present
|
10
|
+
|
11
|
+
def self.new_from_hash(hash={})
|
12
|
+
new_instance = new('',[])
|
13
|
+
return new_instance.from_hash(hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def levels_present
|
17
|
+
if self.levels.present?
|
18
|
+
self.levels.each do |level|
|
19
|
+
level.validate
|
20
|
+
errors.push(*level.errors)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
errors << 'Levels Required for Hierarchy'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def from_hash(working_hash)
|
28
|
+
return self if working_hash.nil?
|
29
|
+
working_hash.stringify_keys!
|
30
|
+
|
31
|
+
parse_name(working_hash.delete('name'))
|
32
|
+
parse_levels(working_hash.delete('levels'))
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_levels(levels_array)
|
37
|
+
return if levels_array.nil? || levels_array.empty?
|
38
|
+
|
39
|
+
levels_array.each do |level_hash|
|
40
|
+
self.levels << ::Rubiks::Level.new_from_hash(level_hash)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
hash = {}
|
46
|
+
|
47
|
+
hash['name'] = self.name.to_s if self.name.present?
|
48
|
+
hash['levels'] = self.levels.map(&:to_hash) if self.levels.present?
|
49
|
+
|
50
|
+
return hash
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubiks/nodes/annotated_node'
|
2
|
+
require 'rubiks/nodes/hierarchy'
|
3
|
+
|
4
|
+
module ::Rubiks
|
5
|
+
|
6
|
+
class Level < ::Rubiks::AnnotatedNode
|
7
|
+
def self.new_from_hash(hash={})
|
8
|
+
new_instance = new
|
9
|
+
return new_instance.from_hash(hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
def from_hash(working_hash)
|
13
|
+
return self if working_hash.nil?
|
14
|
+
working_hash.stringify_keys!
|
15
|
+
|
16
|
+
parse_name(working_hash.delete('name'))
|
17
|
+
return self
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
hash = {}
|
22
|
+
|
23
|
+
hash['name'] = self.name.to_s if self.name.present?
|
24
|
+
|
25
|
+
return hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubiks/nodes/validated_node'
|
2
|
+
|
3
|
+
module ::Rubiks
|
4
|
+
|
5
|
+
class Measure < ::Rubiks::AnnotatedNode
|
6
|
+
value :column, String
|
7
|
+
value :aggregator, String
|
8
|
+
value :format_string, String
|
9
|
+
|
10
|
+
validates :column_present, :aggregator_present
|
11
|
+
|
12
|
+
def self.new_from_hash(hash={})
|
13
|
+
new_instance = new
|
14
|
+
return new_instance.from_hash(hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
def from_hash(working_hash)
|
18
|
+
return self if working_hash.nil?
|
19
|
+
working_hash.stringify_keys!
|
20
|
+
|
21
|
+
parse_name(working_hash.delete('name'))
|
22
|
+
parse_column(working_hash.delete('column'))
|
23
|
+
parse_aggregator(working_hash.delete('aggregator'))
|
24
|
+
parse_format_string(working_hash.delete('format_string'))
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hash
|
29
|
+
hash = {}
|
30
|
+
|
31
|
+
hash['name'] = self.name.to_s if self.name.present?
|
32
|
+
hash['column'] = self.column.to_s if self.column.present?
|
33
|
+
hash['aggregator'] = self.aggregator.to_s if self.aggregator.present?
|
34
|
+
hash['format_string'] = self.format_string.to_s if self.format_string.present?
|
35
|
+
|
36
|
+
return hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def column_present
|
40
|
+
errors << 'Column required on Measure' if self.column.blank?
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_column(column_value)
|
44
|
+
return if column_value.nil?
|
45
|
+
|
46
|
+
self.column = column_value.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def aggregator_present
|
50
|
+
errors << 'Aggregator required on Measure' if self.aggregator.blank?
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_aggregator(aggregator_value)
|
54
|
+
return if aggregator_value.nil?
|
55
|
+
|
56
|
+
self.aggregator = aggregator_value.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_format_string(format_string_value)
|
60
|
+
return if format_string_value.nil?
|
61
|
+
|
62
|
+
self.format_string = format_string_value.to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rubiks/nodes/validated_node'
|
2
|
+
require 'rubiks/nodes/cube'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module ::Rubiks
|
6
|
+
|
7
|
+
class Schema < ::Rubiks::ValidatedNode
|
8
|
+
child :cubes, [::Rubiks::Cube]
|
9
|
+
|
10
|
+
validates :cubes_present
|
11
|
+
|
12
|
+
def self.new_from_hash(hash={})
|
13
|
+
new_instance = new([])
|
14
|
+
return new_instance.from_hash(hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
def cubes_present
|
18
|
+
if self.cubes.present?
|
19
|
+
self.cubes.each do |cube|
|
20
|
+
cube.validate
|
21
|
+
errors.push(*cube.errors)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
errors << 'Cubes Required for Schema'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_hash(working_hash)
|
29
|
+
return self if working_hash.nil?
|
30
|
+
working_hash.stringify_keys!
|
31
|
+
|
32
|
+
parse_cubes(working_hash.delete('cubes'))
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_cubes(cubes_array)
|
37
|
+
return if cubes_array.nil? || cubes_array.empty?
|
38
|
+
|
39
|
+
cubes_array.each do |cube_hash|
|
40
|
+
self.cubes << ::Rubiks::Cube.new_from_hash(cube_hash)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
hash = {}
|
46
|
+
|
47
|
+
hash['cubes'] = self.cubes.map(&:to_hash) if self.cubes.present?
|
48
|
+
|
49
|
+
return hash
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json
|
53
|
+
MultiJson.dump(to_hash)
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_xml
|
57
|
+
to_hash.to_xml(:root => 'Schema')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rltk'
|
2
|
+
require 'rltk/ast'
|
3
|
+
|
4
|
+
module ::Rubiks
|
5
|
+
class ValidatedNode < ::RLTK::ASTNode
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :validators
|
9
|
+
|
10
|
+
alias_method :validator_methods, :validators
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.validates(*validator_symbols)
|
14
|
+
@validators ||= []
|
15
|
+
@validators << validator_symbols.flatten
|
16
|
+
@validators.flatten!
|
17
|
+
@validators.compact!
|
18
|
+
@validators.uniq!
|
19
|
+
|
20
|
+
return @validators
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.inherited(klass)
|
24
|
+
super
|
25
|
+
klass.validators = self.validators.nil? ?
|
26
|
+
[] :
|
27
|
+
self.validators.dup
|
28
|
+
end
|
29
|
+
|
30
|
+
def errors
|
31
|
+
@errors ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid?
|
35
|
+
validate if errors.empty?
|
36
|
+
|
37
|
+
return errors.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate
|
41
|
+
self.class.validator_methods.each do |validator_method|
|
42
|
+
self.__send__(validator_method) if respond_to?(validator_method)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/rubiks/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Rubiks
|
2
|
-
VERSION = '0.0.
|
1
|
+
module ::Rubiks
|
2
|
+
VERSION = '0.0.4'
|
3
3
|
end
|
data/lib/rubiks.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'rubiks/version'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
require 'active_support/core_ext/hash/deep_dup'
|
5
|
+
require 'active_support/core_ext/hash/keys'
|
6
|
+
require 'active_support/core_ext/hash/conversions'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
end
|
8
|
+
nodes_directory = File.expand_path('../rubiks/nodes', __FILE__)
|
9
|
+
Dir["#{nodes_directory}/*.rb"].each { |file| require file }
|
data/rubiks.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Rubiks::VERSION
|
9
9
|
gem.authors = ['JohnnyT']
|
10
10
|
gem.email = ['johnnyt@moneydesktop.com']
|
11
|
-
gem.description = %q{
|
12
|
-
gem.summary = gem.
|
11
|
+
gem.description = %q{Define an OLAP schema}
|
12
|
+
gem.summary = 'Rubiks is a Ruby gem that defines an OLAP schema and can output the schema as XML and JSON.'
|
13
13
|
gem.homepage = 'https://github.com/moneydesktop/rubiks'
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
@@ -17,15 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ['lib']
|
19
19
|
|
20
|
-
gem.add_dependency '
|
21
|
-
|
22
|
-
gem.
|
23
|
-
gem.add_development_dependency 'guard'
|
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'
|
29
|
-
gem.add_development_dependency 'simplecov'
|
30
|
-
gem.add_development_dependency 'simplecov-gem-adapter'
|
20
|
+
gem.add_dependency 'rltk'
|
21
|
+
gem.add_dependency 'activesupport'
|
22
|
+
gem.add_dependency 'builder'
|
31
23
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# This example is taken from the Mondrian documentation:
|
4
|
+
# http://mondrian.pentaho.com/documentation/schema.php#Cubes_and_dimensions
|
5
|
+
# and then modified to use Rails/Rubiks conventions
|
6
|
+
#
|
7
|
+
# We want the output to be:
|
8
|
+
#
|
9
|
+
# <Schema>
|
10
|
+
# <Cube name="Sales">
|
11
|
+
# <Table name="view_sales"/>
|
12
|
+
#
|
13
|
+
# <Dimension name="Gender" foreignKey="customer_id">
|
14
|
+
# <Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="id">
|
15
|
+
# <Table name="customers"/>
|
16
|
+
# <Level name="Gender" column="gender" uniqueMembers="true"/>
|
17
|
+
# </Hierarchy>
|
18
|
+
# </Dimension>
|
19
|
+
#
|
20
|
+
# <Dimension name="Date" foreignKey="date_id">
|
21
|
+
# <Hierarchy hasAll="false" primaryKey="id">
|
22
|
+
# <Table name="view_dates"/>
|
23
|
+
# <Level name="Year" column="year" type="Numeric" uniqueMembers="true"/>
|
24
|
+
# <Level name="Quarter" column="quarter" uniqueMembers="false"/>
|
25
|
+
# <Level name="Month" column="month_of_year" type="Numeric" uniqueMembers="false"/>
|
26
|
+
# </Hierarchy>
|
27
|
+
# </Dimension>
|
28
|
+
#
|
29
|
+
# <Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###"/>
|
30
|
+
# <Measure name="Store Sales" column="store_sales" aggregator="sum" formatString="#,###.##"/>
|
31
|
+
# <Measure name="Store Cost" column="store_cost" aggregator="sum" formatString="#,###.00"/>
|
32
|
+
#
|
33
|
+
# <CalculatedMember name="Profit" dimension="Measures" formula="[Measures].[Store Sales] - [Measures].[Store Cost]">
|
34
|
+
# <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
|
35
|
+
# </CalculatedMember>
|
36
|
+
# </Cube>
|
37
|
+
# </Schema>
|
38
|
+
|
39
|
+
describe 'A basic Mondrian XML Schema' do
|
40
|
+
let(:described_class) { ::Rubiks::Schema }
|
41
|
+
let(:schema_hash) {
|
42
|
+
{
|
43
|
+
'cubes' => [{
|
44
|
+
'name' => 'sales',
|
45
|
+
'measures' => [
|
46
|
+
{
|
47
|
+
'name' => 'unit_sales',
|
48
|
+
'aggregator' => 'sum',
|
49
|
+
'format_string' => '#,###'
|
50
|
+
},
|
51
|
+
{
|
52
|
+
'name' => 'store_sales',
|
53
|
+
'aggregator' => 'sum',
|
54
|
+
'format_string' => '#,###.##'
|
55
|
+
},
|
56
|
+
{
|
57
|
+
'name' => 'store_cost',
|
58
|
+
'aggregator' => 'sum',
|
59
|
+
'format_string' => '#,###.00'
|
60
|
+
}
|
61
|
+
],
|
62
|
+
'dimensions' => [
|
63
|
+
{
|
64
|
+
'name' => 'date',
|
65
|
+
'hierarchies' => [{
|
66
|
+
'name' => 'day_of_week',
|
67
|
+
'levels' => [{
|
68
|
+
'name' => 'day_of_week'
|
69
|
+
}]
|
70
|
+
}]
|
71
|
+
}
|
72
|
+
]
|
73
|
+
}]
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
# subject { described_class.new_from_hash(schema_hash) }
|
78
|
+
|
79
|
+
# describe '#to_json' do
|
80
|
+
# it 'generates a JSON string' do
|
81
|
+
# subject.to_json.should be_kind_of String
|
82
|
+
# end
|
83
|
+
|
84
|
+
# it 'generates a valid JSON string' do
|
85
|
+
# lambda {
|
86
|
+
# MultiJson.load(subject.to_json)
|
87
|
+
# }.should_not raise_error MultiJson::LoadError
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# describe ::Rubiks::AnnotatedNode do
|
4
|
+
# # API
|
5
|
+
# specify { subject.respond_to?(:from_hash) }
|
6
|
+
# specify { subject.respond_to?(:to_hash) }
|
7
|
+
#
|
8
|
+
# context 'when parsed from a valid hash' do
|
9
|
+
# subject { described_class.new.from_hash('name' => 'some_name') }
|
10
|
+
#
|
11
|
+
# its(:name) { should eq('some_name') }
|
12
|
+
#
|
13
|
+
# its(:to_hash) { should have_key('name') }
|
14
|
+
#
|
15
|
+
# it { should be_valid }
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# context 'when parsed from an invalid (empty) hash' do
|
19
|
+
# subject { described_class.new.from_hash({}) }
|
20
|
+
#
|
21
|
+
# it { should_not be_valid }
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# end
|