shades 0.15 → 0.16

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MDdiMzYxZDQzNDdmOTU2NDI5MTU2YTliYmQ0NDNiNjdjN2ExOTBkOA==
4
+ MzlmYmQ3MTc0MTQ5NWM3MjNlMDBhNzU5MGIzMDM2ODk4NmQ0OTcyOQ==
5
5
  data.tar.gz: !binary |-
6
- MGY3NTM1OGI3MDZiMTE0NzcwNmMwYzQ5MjAyYzdjYzE4M2IwMGZjOA==
6
+ OWM3ZjJjNDE5NzI4OGU0MWM3NmRhNzAzOWI5NGVjMmNjYTQ3ZmEwOQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZGY5MzNmYTM2NTdkZjRjMTViNzA0MmFlN2NjNjAwM2JiNGY0ZWU0ZmE1YWMz
10
- ZTg0NTViZTJmY2I0ZTIyOGFmNjk0N2Y5YjcwZDQ3N2RhZjNjMDlmNjBiOGYy
11
- YWRjZDA4YzZjMGQyYmRhMzkwOTA3ZTU5NmMzM2VjMjVmYWU3OTM=
9
+ MGVkM2YxOWEwNzgyMWM2NzBlNTViOGY0ZjQ5YjEyMDg2OTY2ZWI0YmFjNWI3
10
+ YTNiOTM2OGI1YjllNmQ3YzM0NjM4ZTA0NDIzYjQzOGI3NDU2ZDQzODdmOWI3
11
+ M2IwMjUxMzJkNmRjODkzMjFmZTk5ODRmNWUwZTYyNzVjNzFmNjA=
12
12
  data.tar.gz: !binary |-
13
- YmU2YTc2YzcwZDMyOGM0NmRkOTA4M2E3MzgwODhiNWFiYjNmMjRkNjJjNDYy
14
- NWUxMzI1YjkyN2JlYmZkOGYxZjFmOGE1NTc5OTExZWNiNmM5ZjM0ZTJjYjMw
15
- MDAzMWEzNWVmZDVkYmVjMGJlYzE3ZTIwNTY5ZDlhZDlhOTFmY2Y=
13
+ ZTc0YzY2NzA1MDgzZGFkNGVhNTY4Njc0ODBmYjY3MzczOTQzN2RhZTdlNjJj
14
+ ZTZhMDZlMmZjMWNlYTJiZWQ4ODY4YjczYjFmZTUwOGM2NmIzZjBmNWI4ZDQw
15
+ NjI0NmZhMGM1OGI1Nzg4ZDIyZjUyZTIwNTI2YmViY2Q0YjllY2M=
data/.gitignore CHANGED
@@ -11,6 +11,7 @@ spec/reports
11
11
  test/tmp
12
12
  test/version_tmp
13
13
  tmp
14
+ Gemfile.lock
14
15
 
15
16
  # YARD artifacts
16
17
  .yardoc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
@@ -1,10 +1,10 @@
1
- require 'model'
2
- require 'cube'
3
- require 'histo'
4
- require 'stats'
5
- require 'streamparser'
6
- require 'queryparser'
7
- require 'formatter'
1
+ require 'shades/model'
2
+ require 'shades/cube'
3
+ require 'shades/histo'
4
+ require 'shades/stats'
5
+ require 'shades/streamparser'
6
+ require 'shades/queryparser'
7
+ require 'shades/formatter'
8
8
 
9
9
  module Shades
10
10
  end
File without changes
File without changes
File without changes
@@ -0,0 +1,34 @@
1
+ module Shades
2
+ grammar QueryGrammar
3
+ rule query
4
+ space* rollup_list
5
+ space* 'by' space* categorization_list:identifier_list
6
+ optional_sorting:( space* 'order by' space* sorting_list:identifier_list )?
7
+ space* <QueryNode>
8
+ end
9
+
10
+ rule space
11
+ [\s]+
12
+ end
13
+
14
+ rule rollup_list
15
+ rollup rest_rollups:( ',' space* rollup )* <RollupListNode>
16
+ end
17
+
18
+ rule rollup
19
+ stat_type '(' measures:identifier_list ')' <RollupNode>
20
+ end
21
+
22
+ rule stat_type
23
+ [\w]+ <StatTypeNode>
24
+ end
25
+
26
+ rule identifier_list
27
+ identifier rest_identifiers:( ',' space* identifier )* <IdentifierListNode>
28
+ end
29
+
30
+ rule identifier
31
+ [\w]+ <IdentifierNode>
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,96 @@
1
+ require "treetop"
2
+
3
+ module Shades
4
+ module QueryGrammar
5
+ class QueryNode < Treetop::Runtime::SyntaxNode
6
+ def rollup_nodes
7
+ rollup_list.to_a
8
+ end
9
+
10
+ def categorization_nodes
11
+ categorization_list.to_a
12
+ end
13
+
14
+ def sorting_nodes
15
+ if optional_sorting.respond_to?(:sorting_list)
16
+ optional_sorting.sorting_list.to_a
17
+ else
18
+ []
19
+ end
20
+ end
21
+ end
22
+
23
+ class RollupListNode < Treetop::Runtime::SyntaxNode
24
+ def to_a
25
+ [rollup] + rest_rollups.elements.map do |comma_and_rollup|
26
+ comma_and_rollup.rollup
27
+ end
28
+ end
29
+ end
30
+
31
+ class IdentifierListNode < Treetop::Runtime::SyntaxNode
32
+ def to_a
33
+ [identifier] + rest_identifiers.elements.map do |comma_and_identifier|
34
+ comma_and_identifier.identifier
35
+ end
36
+ end
37
+ end
38
+
39
+ class RollupNode < Treetop::Runtime::SyntaxNode
40
+ def stat_type_name
41
+ stat_type.text_value
42
+ end
43
+
44
+ def measure_names
45
+ measures.to_a.map(&:text_value)
46
+ end
47
+ end
48
+
49
+ class StatTypeNode < Treetop::Runtime::SyntaxNode
50
+ end
51
+
52
+ class IdentifierNode < Treetop::Runtime::SyntaxNode
53
+ def name
54
+ text_value
55
+ end
56
+ end
57
+ end
58
+
59
+ class QueryParser
60
+ def self.parse(qs, query_factory = Query)
61
+ @parser_class ||= Treetop.load(File.join(File.dirname(__FILE__), "query.treetop"))
62
+
63
+ parser = @parser_class.new
64
+ unless query_node = parser.parse(qs)
65
+ raise ArgumentError, "Cannot parse query at character #{parser.index}"
66
+ end
67
+
68
+ query_factory.new(
69
+ :rollups => rollups_from_nodes(query_node.rollup_nodes),
70
+ :categorizations => categorizations_from_nodes(query_node.categorization_nodes),
71
+ :sorting => sorting_from_nodes(query_node.sorting_nodes)
72
+ )
73
+ end
74
+
75
+ def self.rollups_from_nodes(nodes)
76
+ nodes.flat_map { |node|
77
+ stat = Stats::StatsType.get(node.stat_type_name)
78
+ node.measure_names.map { |measure_name|
79
+ { :stat => stat, :measure => measure_name }
80
+ }
81
+ }
82
+ end
83
+
84
+ def self.categorizations_from_nodes(nodes)
85
+ nodes.map { |categorization|
86
+ categorization.name
87
+ }
88
+ end
89
+
90
+ def self.sorting_from_nodes(nodes)
91
+ nodes.map { |sorting|
92
+ { :key => sorting.name, :asc => true }
93
+ }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,10 @@
1
+ require 'shades/model'
2
+ require 'shades/cube'
3
+ require 'shades/histo'
4
+ require 'shades/stats'
5
+ require 'shades/streamparser'
6
+ require 'shades/queryparser'
7
+ require 'shades/formatter'
8
+
9
+ module Shades
10
+ end
File without changes
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'shades'
3
- s.version = '0.15'
3
+ s.version = '0.16'
4
4
 
5
5
  s.summary = "Get a new perspective on your data. In-memory data cubing of event data for Ruby."
6
6
  s.description = <<-EOF
@@ -12,6 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.require_paths = %w[lib]
13
13
  s.executables = ["shades", "histo"]
14
14
 
15
+ s.add_dependency 'treetop', '~> 1.4.14'
16
+
15
17
  s.add_development_dependency 'rake-compiler'
16
18
  s.add_development_dependency 'rspec'
17
19
  s.add_development_dependency 'rdoc'
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module Shades
5
+ describe QueryParser do
6
+ it "parses rollups out of the query expression" do
7
+ query = QueryParser.parse("sum(amount) by transactionid", OpenStruct)
8
+
9
+ expect(query.rollups.length).to eq(1)
10
+ expect(query.rollups[0][:measure]).to eq("amount")
11
+ expect(query.rollups[0][:stat]).to eq(Stats::SUM)
12
+ end
13
+
14
+ it "parses multiple rollups out of the query expression" do
15
+ query = QueryParser.parse("sum(amount), max(quantity) by transactionid", OpenStruct)
16
+
17
+ expect(query.rollups.length).to eq(2)
18
+ expect(query.rollups[0][:measure]).to eq("amount")
19
+ expect(query.rollups[1][:measure]).to eq("quantity")
20
+ end
21
+
22
+ it "parses categorizations out of the query expression" do
23
+ query = QueryParser.parse("sum(amount) by transactionid", OpenStruct)
24
+ expect(query.categorizations).to eq(["transactionid"])
25
+ end
26
+
27
+ it "parses multiple categorizations out of the query expression" do
28
+ query = QueryParser.parse("sum(amount) by customer, item", OpenStruct)
29
+ expect(query.categorizations).to eq(["customer", "item"])
30
+ end
31
+
32
+ it "parses sort descriptions out of the query expression" do
33
+ query = QueryParser.parse("sum(amount) by transactionid order by amount", OpenStruct)
34
+
35
+ expect(query.sorting.length).to eq(1)
36
+ expect(query.sorting[0][:key]).to eq("amount")
37
+ expect(query.sorting[0][:asc]).to eq(true)
38
+ end
39
+
40
+ it "parses multiple sort descriptions out of the query expression" do
41
+ query = QueryParser.parse("sum(amount) by transactionid order by amount, customerid", OpenStruct)
42
+
43
+ expect(query.sorting.length).to eq(2)
44
+ expect(query.sorting[0][:key]).to eq("amount")
45
+ expect(query.sorting[1][:key]).to eq("customerid")
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ require 'shades'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ config.order = 'random'
9
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shades
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.15'
4
+ version: '0.16'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dietrich Featherston
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-08 00:00:00.000000000 Z
11
+ date: 2013-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: treetop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.14
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.14
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rake-compiler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -63,31 +77,38 @@ executables:
63
77
  extensions: []
64
78
  extra_rdoc_files:
65
79
  - README.md
66
- - lib/cube.rb
67
- - lib/formatter.rb
68
- - lib/histo.rb
69
- - lib/model.rb
70
- - lib/queryparser.rb
80
+ - lib/shades/cube.rb
81
+ - lib/shades/formatter.rb
82
+ - lib/shades/histo.rb
83
+ - lib/shades/model.rb
84
+ - lib/shades/queryparser.rb
85
+ - lib/shades/shades.rb
86
+ - lib/shades/stats.rb
87
+ - lib/shades/streamparser.rb
71
88
  - lib/shades.rb
72
- - lib/stats.rb
73
- - lib/streamparser.rb
74
89
  files:
75
90
  - .gitignore
91
+ - .rspec
92
+ - Gemfile
76
93
  - LICENSE
77
94
  - README.md
78
95
  - Rakefile
79
96
  - bin/histo
80
97
  - bin/shades
81
- - lib/cube.rb
82
- - lib/formatter.rb
83
- - lib/histo.rb
84
- - lib/model.rb
85
- - lib/queryparser.rb
86
98
  - lib/shades.rb
87
- - lib/stats.rb
88
- - lib/streamparser.rb
99
+ - lib/shades/cube.rb
100
+ - lib/shades/formatter.rb
101
+ - lib/shades/histo.rb
102
+ - lib/shades/model.rb
103
+ - lib/shades/query.treetop
104
+ - lib/shades/queryparser.rb
105
+ - lib/shades/shades.rb
106
+ - lib/shades/stats.rb
107
+ - lib/shades/streamparser.rb
89
108
  - script/build-ctags
90
109
  - shades.gemspec
110
+ - spec/queryparser_spec.rb
111
+ - spec/spec_helper.rb
91
112
  - transactions.txt
92
113
  homepage: https://github.com/d2fn/shades-rb
93
114
  licenses:
@@ -115,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
136
  version: '0'
116
137
  requirements: []
117
138
  rubyforge_project: shades
118
- rubygems_version: 2.0.3
139
+ rubygems_version: 2.0.7
119
140
  signing_key:
120
141
  specification_version: 4
121
142
  summary: Get a new perspective on your data. In-memory data cubing of event data for
@@ -1,167 +0,0 @@
1
- module Shades
2
-
3
- ## queries are of the form:
4
- ## <stat-type> <measure>[, [<stat-type>] <measure>]* by <dimension>[, <dimension>] order by <dimension|measure>[, <dimension|measure>]*
5
- ## for example, to get the mean load1, and load5 measures by unique combination of host role and kernel version:
6
- ## mean load1, load5 by role, kernelversion
7
- class QueryParser
8
-
9
- def self.parse(qs)
10
- parts = qs.scan(/[\w\.]+/)
11
- tokens = []
12
- t = BeginRollupToken.new
13
- parts.each do |p|
14
- t = t.emit(p)
15
- tokens << t
16
- end
17
- rollups = rollups_pass(tokens)
18
- categorizations = categorizations_pass(tokens)
19
- sorting = sorting_pass(tokens)
20
- Query.new(:categorizations => categorizations, :rollups => rollups, :sorting => sorting)
21
- end
22
-
23
- def self.rollups_pass(tokens)
24
- stat = nil
25
- r = []
26
- tokens.each do |t|
27
- if t.kind_of? StatTypeToken
28
- stat = t.stat
29
- elsif t.kind_of? MeasureRefToken
30
- r << { :measure => t.text, :stat => stat }
31
- end
32
- end
33
- r
34
- end
35
-
36
- def self.categorizations_pass(tokens)
37
- d = []
38
- tokens.each do |t|
39
- if t.kind_of? DimensionRefToken
40
- d << t.text
41
- end
42
- end
43
- d
44
- end
45
-
46
- def self.sorting_pass(tokens)
47
- s = []
48
- tokens.each do |t|
49
- if t.kind_of? SortKeyToken
50
- s << { :key => t.text, :asc => true }
51
- end
52
- end
53
- s
54
- end
55
- end
56
-
57
- class Token
58
- attr_accessor :text
59
- def initialize(s)
60
- @text = s
61
- end
62
- def to_s
63
- @text
64
- end
65
- end
66
-
67
- class BeginRollupToken < Token
68
- def initialize
69
- super("<begin>")
70
- end
71
- def emit(s)
72
- StatTypeToken::parse(s)
73
- end
74
- end
75
-
76
- class StatTypeToken < Token
77
- attr_accessor :stat
78
- def initialize(name, stat)
79
- super(name)
80
- @stat = stat
81
- end
82
-
83
- ## context free parsing of the next token to be called by the prior token
84
- def self.parse(s)
85
- stat = Stats::StatsType::get(s)
86
- if stat.nil?
87
- nil
88
- else
89
- StatTypeToken.new(s, stat)
90
- end
91
- end
92
-
93
- ## given the next string, parse and return the next token
94
- def emit(s)
95
- # a measure must always follow a stat
96
- MeasureRefToken::parse(s)
97
- end
98
- end
99
-
100
- class MeasureRefToken < Token
101
- def self.parse(s)
102
- MeasureRefToken.new(s)
103
- end
104
- def emit(s)
105
- if s.downcase.eql?("by")
106
- BeginCategorizationToken::parse(s)
107
- else
108
- t = StatTypeToken::parse(s)
109
- if !t.nil?
110
- t
111
- else
112
- MeasureRefToken::parse(s)
113
- end
114
- end
115
- end
116
- end
117
-
118
- class BeginCategorizationToken < Token
119
- def self.parse(s)
120
- BeginCategorizationToken.new(s)
121
- end
122
- def emit(s)
123
- DimensionRefToken::parse(s)
124
- end
125
- end
126
-
127
- class DimensionRefToken < Token
128
- def self.parse(s)
129
- DimensionRefToken.new(s)
130
- end
131
- def emit(s)
132
- if s.downcase.eql?("order")
133
- OrderToken::parse(s)
134
- else
135
- DimensionRefToken::parse(s)
136
- end
137
- end
138
- end
139
-
140
- class OrderToken < Token
141
- def self.parse(s)
142
- OrderToken.new(s)
143
- end
144
- def emit(s)
145
- # by
146
- BeginSortingToken::parse(s)
147
- end
148
- end
149
-
150
- class BeginSortingToken < Token
151
- def self.parse(s)
152
- BeginSortingToken.new(s)
153
- end
154
- def emit(s)
155
- SortKeyToken::parse(s)
156
- end
157
- end
158
-
159
- class SortKeyToken < Token
160
- def self.parse(s)
161
- SortKeyToken.new(s)
162
- end
163
- def emit(s)
164
- SortKeyToken::parse(s)
165
- end
166
- end
167
- end