Skip to content
This repository has been archived by the owner on Jan 19, 2023. It is now read-only.

Commit

Permalink
Add UI schema spec
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnnyT committed Apr 25, 2013
1 parent ace4079 commit b174e9a
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 38 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -13,6 +13,7 @@ group :test do
gem 'rspec'
gem 'rspec-pride'
gem 'equivalent-xml'
gem 'json_expressions'
end

group :development do
Expand Down
3 changes: 2 additions & 1 deletion lib/rubiks/calculated_measure.rb
Expand Up @@ -14,7 +14,8 @@ def format_string(new_value=nil, options={})
def to_xml(builder = nil)
builder = builder || new_builder

xml_attrs = {:name => caption, :dimension => 'Measures'}
xml_attrs = default_xml_attributes
xml_attrs[:dimension] = 'Measures'
xml_attrs[:formula] = formula if formula.present?
xml_attrs[:formatString] = format_string if format_string.present?

Expand Down
43 changes: 41 additions & 2 deletions lib/rubiks/cube.rb
@@ -1,6 +1,26 @@
module ::Rubiks

class Cube < NamedObject
def date_dimension(new_value=nil)
@date_dimension = new_value.to_s if new_value.present?
@date_dimension ||= @options[:date_dimension]
end

def person_dimension(new_value=nil)
@person_dimension = new_value.to_s if new_value.present?
@person_dimension ||= @options[:person_dimension]
end

def count_measure(new_value=nil)
@count_measure = new_value.to_s if new_value.present?
@count_measure ||= @options[:count_measure]
end

def person_count_measure(new_value=nil)
@person_count_measure = new_value.to_s if new_value.present?
@person_count_measure ||= @options[:person_count_measure]
end

def dimensions
@dimensions ||= []
end
Expand Down Expand Up @@ -43,16 +63,35 @@ def calculated_measure(calculated_measure_name, options={}, &block)
new_calculated_measure
end

def json_hash
hash = default_json_attributes.merge(
:date_dimension => date_dimension,
:person_dimension => person_dimension,
:count_measure => count_measure,
:person_count_measure => person_count_measure
)
hash[:dimensions] = dimensions.map{ |dim| dim.to_json }
hash[:measures] = json_measures if json_measures.present?
hash.delete_if { |key,value| value.nil? }
end

def to_xml(builder = nil)
builder = builder || new_builder

builder.cube(:name => caption) do
builder.table(:name => "view_#{name.tableize}")
builder.cube(default_xml_attributes) do
builder.table(:name => table_name)
dimensions.each{ |dimension| dimension.to_xml(builder) }
measures.each{ |measure| measure.to_xml(builder) }
calculated_measures.each{ |measure| measure.to_xml(builder) }
end
end

def json_measures
json_measures = []
json_measures.push(*measures.map{ |m| m.json_hash })
json_measures.push(*calculated_measures.map{ |cm| cm.json_hash })
json_measures
end
end

end
9 changes: 8 additions & 1 deletion lib/rubiks/dimension.rb
@@ -1,6 +1,11 @@
module ::Rubiks

class Dimension < NamedObject
def type(new_value=nil)
@type = new_value.to_s if new_value.present?
@type ||= @options[:type]
end

def hierarchies
@hierarchies ||= []
end
Expand All @@ -19,7 +24,9 @@ def hierarchy(hierarchy_name, options={}, &block)
def to_xml(builder = nil)
builder = builder || new_builder

builder.dimension(:name => caption, :foreignKey => "#{name}_id") do
xml_attrs = default_xml_attributes.merge(:foreignKey => "#{name}_id")
xml_attrs[:type] = type if type.present?
builder.dimension(xml_attrs) do
hierarchies.each{ |hierarchy| hierarchy.to_xml(builder) }
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubiks/hierarchy.rb
Expand Up @@ -19,7 +19,7 @@ def has_all(new_value=nil)
def to_xml(builder = nil)
builder = builder || new_builder

builder.hierarchy(:name => caption, :primaryKey => 'id', :hasAll => has_all.to_s) do
builder.hierarchy(default_xml_attributes.merge(:primaryKey => 'id', :hasAll => has_all.to_s)) do
builder.table(:name => table_name)
levels.each{ |level| level.to_xml(builder) }
end
Expand Down
34 changes: 29 additions & 5 deletions lib/rubiks/level.rb
@@ -1,6 +1,21 @@
module ::Rubiks

class Level < ::Rubiks::NamedObject
def cardinality(new_value=nil)
@cardinality = new_value.to_s if new_value.present?
@cardinality ||= @options[:cardinality]
end

def contiguous(new_value=nil)
@contiguous = new_value.to_s if new_value.present?
@contiguous ||= @options.key?(:contiguous) ? @options[:contiguous].to_s : nil
end

def column(new_value=nil)
@column = new_value.to_s if new_value.present?
@column ||= @options[:column] || name
end

def name_column(new_value=nil)
@name_column = new_value.to_s if new_value.present?
@name_column ||= @options[:name_column]
Expand All @@ -16,16 +31,25 @@ def level_type(new_value=nil)
@level_type ||= @options[:level_type]
end

def data_type(new_value=nil)
@data_type = new_value if new_value.present?
@data_type ||= @options[:data_type]
def type(new_value=nil)
@type = new_value if new_value.present?
@type ||= @options[:type]
end

def json_hash
hash = default_json_attributes
hash[:cardinality] = cardinality.to_s if cardinality.present?
hash[:visible] = visible if visible.present? && visible == 'false'
hash[:contiguous] = contiguous if contiguous.present? && contiguous == 'true'
hash
end

def to_xml(builder = nil)
builder = builder || new_builder

xml_attrs = {:name => caption, :column => column}
xml_attrs[:type] = data_type.to_s.titleize if data_type.present?
xml_attrs = default_xml_attributes.merge(:column => column)
xml_attrs[:levelType] = level_type if level_type.present?
xml_attrs[:type] = type.to_s.capitalize if type.present?
builder.level(xml_attrs)
end
end
Expand Down
36 changes: 28 additions & 8 deletions lib/rubiks/named_object.rb
Expand Up @@ -11,14 +11,19 @@ def name(new_value=nil)
@name ||= @options[:name] || 'default'
end

def icon_type(new_value=nil)
@icon_type = new_value.to_s if new_value.present?
@icon_type ||= @options[:icon_type]
end

def description(new_value=nil)
@description = new_value.to_s if new_value.present?
@description ||= @options[:description]
end

def is_visible(new_value=nil)
@is_visible = new_value.to_s if new_value.present?
@is_visible ||= @options[:is_visible] || true
def visible(new_value=nil)
@visible = new_value.to_s unless new_value.nil?
@visible ||= @options.key?(:visible) ? @options[:visible].to_s : nil
end

def column(new_value=nil)
Expand All @@ -36,16 +41,31 @@ def table_name(new_value=nil)
@table_name ||= @options[:table_name] || "view_#{name.tableize}"
end

def json_hash
{
def to_json
MultiJson.dump(json_hash)
end

def default_json_attributes
json_attrs = {
:name => name,
:caption => caption
:caption => caption,
:description => description,
:icon_type => icon_type
}
json_attrs[:visible] = visible if visible.present? && visible == 'false'
json_attrs.delete_if { |key,value| value.nil? }
end
alias_method :json_hash, :default_json_attributes

def to_json
MultiJson.dump(json_hash)
def default_xml_attributes
xml_attrs = {
:name => caption,
:description => description
}
xml_attrs[:visible] = visible if visible.present? && visible == 'false'
xml_attrs.delete_if { |key,value| value.nil? }
end
alias_method :xml_hash, :default_xml_attributes

def to_xml(builder = nil)
return if name.blank?
Expand Down
14 changes: 9 additions & 5 deletions lib/rubiks/schema.rb
@@ -1,11 +1,9 @@
module ::Rubiks

class Schema < NamedObject
def self.define(&block)
raise ArgumentError, 'A block is required' unless block_given?

schema = new
schema.instance_eval(&block)
def self.define(schema_name=nil, options={}, &block)
schema = new(schema_name, options)
schema.instance_eval(&block) if block_given?
schema
end

Expand All @@ -23,6 +21,12 @@ def cube(cube_name, options={}, &block)
new_cube
end

def json_hash
hash = default_json_attributes
hash[:cubes] = cubes.map{ |c| c.to_json } if cubes.present?
hash
end

def to_xml(builder = nil)
builder = builder || new_builder

Expand Down
16 changes: 8 additions & 8 deletions spec/examples/simple_mondrian_schema_spec.rb
Expand Up @@ -7,11 +7,11 @@

cube :sales do
name :sales
dimension :date do
dimension :date, :type => 'TimeDimension' do
hierarchy :year_quarter_month do
level :year, :data_type => :numeric
level :quarter, :data_type => :string
level :month, :data_type => :numeric
level :year, :type => :numeric, :level_type => 'TimeYears'
level :quarter, :type => :string, :level_type => 'TimeQuarters'
level :month, :type => :numeric, :level_type => 'TimeMonths'
end
end
measure :sales, :aggregator => 'sum', :format_string => '$#,###'
Expand All @@ -26,12 +26,12 @@
<schema name="Sales">
<cube name="Sales">
<table name="view_sales"/>
<dimension name="Date" foreignKey="date_id">
<dimension name="Date" foreignKey="date_id" type="TimeDimension">
<hierarchy name="Year Quarter Month" primaryKey="id" hasAll="true">
<table name="view_dates"/>
<level name="Year" column="year" type="Numeric"/>
<level name="Quarter" column="quarter" type="String"/>
<level name="Month" column="month" type="Numeric"/>
<level name="Year" column="year" type="Numeric" levelType="TimeYears"/>
<level name="Quarter" column="quarter" type="String" levelType="TimeQuarters"/>
<level name="Month" column="month" type="Numeric" levelType="TimeMonths"/>
</hierarchy>
</dimension>
<measure name="Sales" aggregator="sum" column="sales" formatString="$#,###"/>
Expand Down
67 changes: 67 additions & 0 deletions spec/examples/ui_schema_spec.rb
@@ -0,0 +1,67 @@
require 'spec_helper'

describe 'A schema with UI specific attributes' do
subject {
::Rubiks::Schema.define :transactions do
cube :transactions, :description => 'Financial transactions', :date_dimension => :date do
dimension :date, :description => 'One row per day' do
hierarchy :year_quarter_month, :description => 'YQM' do
level :year, :type => :numeric, :description => 'Year', :contiguous => true
level :quarter, :type => :string, :description => 'Quarter', :contiguous => true
level :month, :type => :numeric, :description => 'Month', :contiguous => true
end
hierarchy :weekday_weekend do
level :weekday_weekend, :type => :string, :contiguous => true, :cardinality => :low
end
end

dimension :client, :visible => false do
hierarchy :name do
level :name, :type => :string, :description => 'Client name'
end
end

measure :sales, :aggregator => 'sum', :format_string => '$#,###'
measure :cost, :aggregator => 'sum', :format_string => '$#,###'
end
end
}

# describe '#json_hash' do
# it 'includes ui attributes' do
# subject.json_hash.should have_key
# binding.pry
# subject.json_hash.should match_json_expression(
# :cubes => {}
# )
# end
# end

its(:to_xml) { should be_equivalent_to(Nokogiri::XML(<<-XML)) }
<schema name="Transactions">
<cube name="Transactions" description="Financial transactions">
<table name="view_transactions"/>
<dimension name="Date" foreignKey="date_id" description="One row per day">
<hierarchy name="Year Quarter Month" primaryKey="id" hasAll="true" description="YQM">
<table name="view_dates"/>
<level name="Year" column="year" type="Numeric" description="Year"/>
<level name="Quarter" column="quarter" type="String" description="Quarter"/>
<level name="Month" column="month" type="Numeric" description="Month"/>
</hierarchy>
<hierarchy name="Weekday Weekend" primaryKey="id" hasAll="true">
<table name="view_dates"/>
<level name="Weekday Weekend" column="weekday_weekend" type="String"/>
</hierarchy>
</dimension>
<dimension name="Client" foreignKey="client_id" visible="false">
<hierarchy name="Name" primaryKey="id" hasAll="true">
<table name="view_clients"/>
<level name="Name" column="name" type="String" description="Client name"/>
</hierarchy>
</dimension>
<measure name="Sales" aggregator="sum" column="sales" formatString="$#,###"/>
<measure name="Cost" aggregator="sum" column="cost" formatString="$#,###"/>
</cube>
</schema>
XML
end
16 changes: 16 additions & 0 deletions spec/rubiks/cube_spec.rb
Expand Up @@ -10,4 +10,20 @@
<table name="view_defaults"/>
</cube>
XML

context 'with calculated measures' do
subject {
cube = described_class.new
cube.calculated_measure :profit
cube
}

its(:json_hash) { should_not have_key :calculated_measures }
its(:json_hash) { should have_key :measures }

it 'adds calculated measures to the measures array' do
subject.json_hash[:measures].length.should eq 1
subject.json_hash[:measures].first[:name].should eq 'profit'
end
end
end
9 changes: 9 additions & 0 deletions spec/rubiks/level_spec.rb
Expand Up @@ -8,4 +8,13 @@
its(:to_xml) { should be_equivalent_to(Nokogiri::XML(<<-XML)) }
<level name="Default" column="default"/>
XML

context 'with UI attributes' do
subject { described_class.new('default', :cardinality => :low, :contiguous => true ) }

its(:json_hash) { should have_key :cardinality }
its(:json_hash) { should have_key :contiguous }

its(:xml_hash) { should_not have_key :cardinality }
end
end

0 comments on commit b174e9a

Please sign in to comment.