shades 0.15 → 0.16

Sign up to get free protection for your applications and to get access to all the features.
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