appstats 0.19.7 → 0.20.0

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.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- appstats (0.19.7)
4
+ appstats (0.20.0)
5
5
  daemons
6
6
  net-scp
7
7
  rails (>= 2.3.0)
@@ -0,0 +1,14 @@
1
+ class CreateAppstatsActionContexts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :appstats_action_context_keys do |t|
4
+ t.string :action_name
5
+ t.string :context_key
6
+ t.string :status
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :appstats_action_context_keys
13
+ end
14
+ end
@@ -10,7 +10,15 @@
10
10
  #
11
11
  # It's strongly recommended to check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(:version => 20110321154125) do
13
+ ActiveRecord::Schema.define(:version => 20110330171745) do
14
+
15
+ create_table "appstats_action_context_keys", :force => true do |t|
16
+ t.string "action_name"
17
+ t.string "context_key"
18
+ t.string "status"
19
+ t.datetime "created_at"
20
+ t.datetime "updated_at"
21
+ end
14
22
 
15
23
  create_table "appstats_actions", :force => true do |t|
16
24
  t.string "name"
@@ -7,6 +7,7 @@ require "#{File.dirname(__FILE__)}/appstats/entry_date"
7
7
  require "#{File.dirname(__FILE__)}/appstats/date_range"
8
8
  require "#{File.dirname(__FILE__)}/appstats/action"
9
9
  require "#{File.dirname(__FILE__)}/appstats/context"
10
+ require "#{File.dirname(__FILE__)}/appstats/action_context_key"
10
11
  require "#{File.dirname(__FILE__)}/appstats/tasks"
11
12
  require "#{File.dirname(__FILE__)}/appstats/logger"
12
13
  require "#{File.dirname(__FILE__)}/appstats/log_collector"
@@ -18,6 +19,7 @@ require "#{File.dirname(__FILE__)}/appstats/result_job"
18
19
  require "#{File.dirname(__FILE__)}/appstats/host"
19
20
  require "#{File.dirname(__FILE__)}/appstats/friendly_timer"
20
21
  require "#{File.dirname(__FILE__)}/appstats/context_key"
22
+ require "#{File.dirname(__FILE__)}/appstats/appstats_query"
21
23
  require "#{File.dirname(__FILE__)}/appstats/context_value"
22
24
  require "#{File.dirname(__FILE__)}/appstats/test_object"
23
25
  require "#{File.dirname(__FILE__)}/appstats/test_query"
@@ -0,0 +1,23 @@
1
+
2
+ module Appstats
3
+ class ActionContextKey < ActiveRecord::Base
4
+ set_table_name "appstats_action_context_keys"
5
+
6
+ attr_accessible :action_name, :context_key, :status
7
+
8
+ def self.update_action_context_keys
9
+ sql = "select action,context_key,count(*) as num
10
+ from appstats_entries
11
+ inner join appstats_contexts on appstats_contexts.appstats_entry_id = appstats_entries.id
12
+ where (action,context_key) not in (select action_name, context_key from appstats_action_context_keys)
13
+ group by action,context_key"
14
+ count = 0
15
+ ActiveRecord::Base.connection.execute(sql).each do |row|
16
+ Appstats::ActionContextKey.create(:action_name => row[0], :context_key => row[1], :status => 'derived')
17
+ count += 1
18
+ end
19
+ count
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,92 @@
1
+ class AppstatsQuery
2
+
3
+ attr_accessor :query
4
+
5
+ @@default_query = "select 0 as num"
6
+
7
+ @@action_to_available_contexts =
8
+ {
9
+ "appstats_queries" => [ "action", "contexts", "group_by" ],
10
+ "bomb" => []
11
+ }
12
+
13
+ def query_to_sql
14
+ return @@default_query if query.nil?
15
+ query.query_to_sql
16
+ end
17
+
18
+ def group_query_to_sql
19
+ return nil if query.nil?
20
+ query.group_query_to_sql
21
+ end
22
+
23
+ def process_query
24
+ return if query.nil?
25
+ query.query_to_sql = @@default_query
26
+ query.group_query_to_sql = nil
27
+ return if query.action.blank?
28
+
29
+ action = query.action.pluralize.downcase
30
+ case action
31
+ when "appstats_queries"
32
+ count_filter = "COUNT(*)"
33
+ query.query_to_sql = "select #{count_filter} as num from appstats_results#{build_where_clause}"
34
+ when "bombs"
35
+ query.query_to_sql = "invalid sql"
36
+ end
37
+ query.group_query_to_sql = query.query_to_sql.sub("#{count_filter} as num","#{context_key_filter_name(action)} as context_key_filter, #{context_value_filter_name(action)} as context_value_filter, COUNT(*) as num") + " group by context_value_filter" unless query.group_by.empty?
38
+ end
39
+
40
+ def run
41
+ query.run
42
+ end
43
+
44
+ def db_connection
45
+ ActiveRecord::Base.connection
46
+ end
47
+
48
+ def self.available_action?(action)
49
+ return false if action.blank?
50
+ return @@action_to_available_contexts.keys.include?(action.downcase.pluralize)
51
+ end
52
+
53
+ private
54
+
55
+ def build_where_clause
56
+ where_clause = ""
57
+ action = query.action.pluralize.downcase
58
+ available_contexts = @@action_to_available_contexts[action]
59
+ status = :context
60
+ query.parsed_contexts.each do |lookup|
61
+ next if status == :context && lookup.kind_of?(String)
62
+ next if status == :join && !lookup.kind_of?(String)
63
+ next if status == :context && (lookup[:context_value].nil? || !available_contexts.include?(lookup[:context_key]))
64
+
65
+ where_clause = " where" if where_clause.blank?
66
+ if lookup.kind_of?(String)
67
+ where_clause += " #{lookup}"
68
+ status = :context
69
+ elsif !lookup[:context_value].nil? && available_contexts.include?(lookup[:context_key])
70
+ where_clause += " #{database_column(action,lookup[:context_key])} #{lookup[:comparator]} '#{Appstats::Query.sqlclean(lookup[:context_value])}'"
71
+ status = :join
72
+ end
73
+ end
74
+ where_clause
75
+ end
76
+
77
+ def context_key_filter_name(action)
78
+ "'" + query.group_by.join(",") + "'"
79
+ end
80
+
81
+ def context_value_filter_name(action)
82
+ database_names = query.group_by.collect do |name|
83
+ database_column(action,name)
84
+ end
85
+ "concat(ifnull("+ database_names.join(",'--'),',',ifnull(") +",'--'))"
86
+ end
87
+
88
+ def database_column(action,name)
89
+ name
90
+ end
91
+
92
+ end
@@ -73,13 +73,27 @@ module Appstats
73
73
  true
74
74
  end
75
75
 
76
+ def self.alpha?(raw_input)
77
+ return false if raw_input.nil?
78
+ !raw_input.match(/^[A-Za-z]+$/i).nil?
79
+ end
80
+
76
81
  def self.parse_constant(current_text,constant)
77
82
  answer = [nil,nil]
78
83
  return answer if current_text.blank? || constant.nil?
79
84
  current_text.strip!
80
- m = current_text.match(/^(#{constant})(.*)$/im)
85
+
86
+ remaining_text_index = -1
87
+ if alpha?(constant)
88
+ m = current_text.match(/^(#{constant})(\s|$)(.*)$/im)
89
+ remaining_text_index = 3
90
+ else
91
+ m = current_text.match(/^(#{constant})(.*)$/im)
92
+ remaining_text_index = 2
93
+ end
94
+
81
95
  answer[0] = m[1] unless m.nil?
82
- answer[1] = m.nil? ? current_text : m[2]
96
+ answer[1] = m.nil? ? current_text : m[remaining_text_index]
83
97
  clean_parsed_word(answer)
84
98
  end
85
99
 
@@ -186,7 +200,7 @@ module Appstats
186
200
  current_token.gsub!(")",'\)')
187
201
  current_token.gsub!("|",'\|')
188
202
  @tokenize_no_spaces<< current_token
189
- current_token = "\\s+#{current_token}" unless current_token.match(/.*[a-z].*/i).nil?
203
+ current_token = "\\s+#{current_token}(\\s|$)" unless current_token.match(/.*[a-z].*/i).nil?
190
204
  @tokenize<< current_token
191
205
  end
192
206
  @tokenize_regex_no_spaces = @tokenize_no_spaces.join("|")
@@ -209,7 +223,7 @@ module Appstats
209
223
  current_rule = rule.upcase
210
224
  current_rule_no_spaces = current_rule
211
225
  @constants_no_spaces<< current_rule_no_spaces
212
- current_rule = "\\s+#{current_rule}" unless current_rule.match(/.*[a-z].*/i).nil?
226
+ current_rule = "\\s+#{current_rule}(\\s|$)" unless current_rule.match(/.*[a-z].*/i).nil?
213
227
  @constants<< current_rule
214
228
  previous_stop_on = :constant
215
229
  end
@@ -1,3 +1,3 @@
1
1
  module Appstats
2
- VERSION = "0.19.7"
2
+ VERSION = "0.20.0"
3
3
  end
@@ -63,6 +63,7 @@ while($running) do
63
63
  Appstats::Host.update_hosts
64
64
  Appstats::ContextKey.update_context_keys
65
65
  Appstats::ContextValue.update_context_values
66
+ Appstats::ActionContextKey.update_action_context_keys
66
67
  Appstats::LogCollector.remove_remote_files(appstats_config["remote_servers"])
67
68
  ActiveRecord::Base.connection.disconnect!
68
69
  end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ module Appstats
4
+ describe ActionContextKey do
5
+
6
+ before(:each) do
7
+ Appstats::Entry.delete_all
8
+ Appstats::Context.delete_all
9
+ Appstats::ActionContextKey.delete_all
10
+ @action = Appstats::ActionContextKey.new
11
+ end
12
+
13
+
14
+
15
+ describe "#initialize" do
16
+
17
+ it "should set action_name to nil" do
18
+ @action.action_name.should == nil
19
+ end
20
+
21
+ it "should set context_key to nil" do
22
+ @action.context_key.should == nil
23
+ end
24
+
25
+ it "should set status to nil" do
26
+ @action.status.should == nil
27
+ end
28
+
29
+ it "should set on constructor" do
30
+ action = Appstats::ActionContextKey.new(:action_name => 'a', :context_key => 'b', :status => 'c')
31
+ action.action_name.should == 'a'
32
+ action.context_key.should == 'b'
33
+ action.status.should == 'c'
34
+ end
35
+
36
+ end
37
+
38
+ describe "#update_action_context_keys" do
39
+
40
+ it "should do nothing if no events" do
41
+ Appstats::ActionContextKey.update_action_context_keys.should == 0
42
+ Appstats::ActionContextKey.count.should == 0
43
+ end
44
+
45
+ it "should ignore actions without any contexts" do
46
+ Appstats::Entry.create_from_logger('a')
47
+ Appstats::ActionContextKey.update_action_context_keys.should == 0
48
+ Appstats::ActionContextKey.count.should == 0
49
+
50
+ end
51
+
52
+ it "should add entry action / context names" do
53
+ Appstats::Entry.create_from_logger('a',:blah => "x")
54
+ Appstats::ActionContextKey.update_action_context_keys.should == 1
55
+ Appstats::ActionContextKey.count.should == 1
56
+
57
+ action = Appstats::ActionContextKey.last
58
+ action.action_name = 'a'
59
+ action.context_key = 'blah'
60
+ action.status = 'derived'
61
+ end
62
+
63
+ it "should ignore existing entries action / context names" do
64
+ Appstats::Entry.create_from_logger('a',:blah => "x")
65
+ Appstats::ActionContextKey.update_action_context_keys.should == 1
66
+ Appstats::ActionContextKey.update_action_context_keys.should == 0
67
+ end
68
+
69
+ it "should ignore duplicates" do
70
+ Appstats::Entry.create_from_logger('a',:blah => "x")
71
+ Appstats::Entry.create_from_logger('a',:blah => "y")
72
+ Appstats::ActionContextKey.update_action_context_keys.should == 1
73
+ Appstats::ActionContextKey.count.should == 1
74
+ end
75
+
76
+
77
+ end
78
+
79
+
80
+ end
81
+ end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ module Appstats
4
+
5
+ describe AppstatsQuery do
6
+
7
+ before(:each) do
8
+ Time.stub!(:now).and_return(Time.parse('2010-09-21 23:15:20'))
9
+ @appstats_query = AppstatsQuery.new
10
+ end
11
+
12
+ describe "#available_action?" do
13
+
14
+ it "should be false for nil" do
15
+ AppstatsQuery.available_action?(nil).should == false
16
+ AppstatsQuery.available_action?("").should == false
17
+ end
18
+
19
+ it "should be false for blah" do
20
+ AppstatsQuery.available_action?("blah").should == false
21
+ end
22
+
23
+ it "should be true for appstats_queries" do
24
+ AppstatsQuery.available_action?("appstats_queries").should == true
25
+ AppstatsQuery.available_action?("Appstats_queries").should == true
26
+ AppstatsQuery.available_action?("appstats_query").should == true
27
+ end
28
+
29
+ end
30
+
31
+ describe "#query_to_sql" do
32
+
33
+ it "should be nil if no query" do
34
+ @appstats_query.query_to_sql.should == "select 0 as num"
35
+ end
36
+
37
+ it "should be based on query" do
38
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries")
39
+ @appstats_query.query_to_sql.should == @appstats_query.query.query_to_sql
40
+ end
41
+
42
+ end
43
+
44
+ describe "#group_query_to_sql" do
45
+
46
+ it "should be nil if no query" do
47
+ @appstats_query.group_query_to_sql.should == nil
48
+ end
49
+
50
+ it "should be based on query" do
51
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries")
52
+ @appstats_query.group_query_to_sql.should == @appstats_query.query.group_query_to_sql
53
+ end
54
+
55
+ end
56
+
57
+ describe "#process_query" do
58
+
59
+ it "should support nil query" do
60
+ @appstats_query.process_query
61
+ @appstats_query.query_to_sql.should == "select 0 as num"
62
+ @appstats_query.group_query_to_sql.should == nil
63
+ end
64
+
65
+ it "should be case insensitive on action" do
66
+ @appstats_query.query = Appstats::Query.new(:query => "# Appstats_Queries", :query_type => "Appstats::AppstatsQuery")
67
+ @appstats_query.process_query
68
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results"
69
+
70
+ @appstats_query.query = Appstats::Query.new(:query => "# aPpstats_Queries", :query_type => "Appstats::AppstatsQuery")
71
+ @appstats_query.process_query
72
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results"
73
+ end
74
+
75
+ it "should support singular names" do
76
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_query", :query_type => "Appstats::AppstatsQuery")
77
+ @appstats_query.process_query
78
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results"
79
+ end
80
+
81
+ it "should handle nil actions" do
82
+ @appstats_query.query = Appstats::Query.new(:query => "", :query_type => "Appstats::AppstatsQuery")
83
+ @appstats_query.process_query
84
+ @appstats_query.query_to_sql.should == "select 0 as num"
85
+ end
86
+
87
+ it "should call query.run" do
88
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries", :query_type => "Appstats::AppstatsQuery")
89
+ @appstats_query.query.stub!(:run).and_return("call-worked")
90
+ @appstats_query.run.should == "call-worked"
91
+ end
92
+
93
+ # THIS IS A SLOW TEST ONLY TO BE RUN IF THINGS START ACTING STRANGE
94
+ it "should actually execute code properly" do
95
+ Result.create
96
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries", :query_type => "Appstats::AppstatsQuery")
97
+ @appstats_query.run.count.should > 0
98
+ end
99
+
100
+ describe "# appstats_queries" do
101
+
102
+ it "should support #appstats_queries" do
103
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries", :query_type => "Appstats::AppstatsQuery")
104
+ @appstats_query.process_query
105
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results"
106
+ @appstats_query.group_query_to_sql.should == nil
107
+ end
108
+
109
+ it "should support where clause for action, contexts, group_by" do
110
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries where action = abc AND contexts = 'def' || group_by like 'hik'", :query_type => "Appstats::AppstatsQuery")
111
+ @appstats_query.process_query
112
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results where action = 'abc' AND contexts = 'def' or group_by like 'hik'"
113
+ @appstats_query.group_query_to_sql.should == nil
114
+ end
115
+
116
+ it "should support group by action, contexts, group_by" do
117
+ @appstats_query.query = Appstats::Query.new(:query => "# appstats_queries group by action, contexts, group_by", :query_type => "Appstats::AppstatsQuery")
118
+ @appstats_query.process_query
119
+ @appstats_query.query_to_sql.should == "select COUNT(*) as num from appstats_results"
120
+ @appstats_query.group_query_to_sql.should == "select 'action,contexts,group_by' as context_key_filter, concat(ifnull(action,'--'),',',ifnull(contexts,'--'),',',ifnull(group_by,'--')) as context_value_filter, COUNT(*) as num from appstats_results group by context_value_filter"
121
+ end
122
+
123
+ # it "should support group by media,network" do
124
+ # @appstats_query.query = Appstats::Query.new(:query => "# buildings group by media, network", :query_type => "Appstats::AppstatsQuery")
125
+ # @appstats_query.process_query
126
+ # @appstats_query.query_to_sql.should == "select COUNT(DISTINCT operator_accesses.id) as num from operator_accesses left join physical_addresses on physical_addresses.id = operator_accesses.physical_address_id left join operator_networks on operator_networks.id = operator_accesses.operator_network_id left join service_providers on service_providers.id = operator_networks.service_provider_id"
127
+ # @appstats_query.group_query_to_sql.should == "select 'media,network' as context_key_filter, concat(media_types.name,',',operator_networks.name) as context_value_filter, COUNT(*) as num from operator_accesses left join physical_addresses on physical_addresses.id = operator_accesses.physical_address_id left join operator_networks on operator_networks.id = operator_accesses.operator_network_id left join service_providers on service_providers.id = operator_networks.service_provider_id group by context_value_filter"
128
+ # end
129
+
130
+ end
131
+ end
132
+
133
+ describe "#db_connection" do
134
+
135
+ it "should use the extract_env" do
136
+ @appstats_query.query = Appstats::Query.new(:query => "# blahs on blah")
137
+ @appstats_query.db_connection.should == ActiveRecord::Base.connection
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -193,18 +193,18 @@ module Appstats
193
193
  end
194
194
 
195
195
  it "should understand an entry without contexts" do
196
- entry = Entry.create_from_logger_string("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
196
+ entry = Entry.create_from_logger_string("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
197
197
  Entry.count.should == @before_count + 1
198
198
  entry.action.should == "address_search"
199
- entry.raw_entry.should == "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
199
+ entry.raw_entry.should == "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
200
200
  entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
201
201
  end
202
202
 
203
203
  it "should understand contexts" do
204
- entry = Entry.create_from_logger_string("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
204
+ entry = Entry.create_from_logger_string("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
205
205
  Entry.count.should == @before_count + 1
206
206
  entry.action.should == "address_filter"
207
- entry.raw_entry.should == "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
207
+ entry.raw_entry.should == "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
208
208
  entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
209
209
  entry.contexts.size.should == 2
210
210
  entry.contexts[0].context_key = "app_name"
@@ -214,10 +214,10 @@ module Appstats
214
214
  end
215
215
 
216
216
  it "should handle 'action' as a context" do
217
- entry = Entry.create_from_logger_string('0.19.7 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
217
+ entry = Entry.create_from_logger_string('0.20.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
218
218
  Entry.count.should == @before_count + 1
219
219
  entry.action.should == "page-view"
220
- entry.raw_entry.should == "0.19.7 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
220
+ entry.raw_entry.should == "0.20.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
221
221
  entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
222
222
  entry.contexts.size.should == 2
223
223
  entry.contexts[0].context_key = "action"
@@ -228,10 +228,10 @@ module Appstats
228
228
  end
229
229
 
230
230
  it "should handle multiple of the same 'context'" do
231
- entry = Entry.create_from_logger_string('0.19.7 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
231
+ entry = Entry.create_from_logger_string('0.20.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
232
232
  Entry.count.should == @before_count + 1
233
233
  entry.action.should == "page-view"
234
- entry.raw_entry.should == "0.19.7 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
234
+ entry.raw_entry.should == "0.20.0 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
235
235
  entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
236
236
  entry.contexts.size.should == 2
237
237
  entry.contexts[0].context_key = "app_name"
@@ -122,12 +122,12 @@ module Appstats
122
122
 
123
123
  it "should accept numbers" do
124
124
  Appstats::Logger.entry(5, :blah => 6)
125
- Appstats::Logger.raw_read.should == ["0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
125
+ Appstats::Logger.raw_read.should == ["0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
126
126
  end
127
127
 
128
128
  it "should accept arrays" do
129
129
  Appstats::Logger.entry('search', :provider => [ 'one', 'two' ])
130
- Appstats::Logger.raw_read.should == ["0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
130
+ Appstats::Logger.raw_read.should == ["0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
131
131
  end
132
132
 
133
133
 
@@ -137,7 +137,7 @@ module Appstats
137
137
 
138
138
  it "should look similar to regular entry" do
139
139
  Appstats::Logger.exception_entry(RuntimeError.new("blah"),:on => "login")
140
- Appstats::Logger.raw_read.should == ["0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
140
+ Appstats::Logger.raw_read.should == ["0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
141
141
  end
142
142
 
143
143
  end
@@ -154,47 +154,47 @@ module Appstats
154
154
 
155
155
  it "should handle a statistics entry" do
156
156
  expected = { :action => "address_search", :timestamp => "2010-09-21 23:15:20" }
157
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
157
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
158
158
  actual.should == expected
159
159
  end
160
160
 
161
161
  it "should handle contexts" do
162
162
  expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
163
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
163
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
164
164
  actual.should == expected
165
165
  end
166
166
 
167
167
  it "should handle multiple actions" do
168
168
  expected = { :action => ["address_filter", "blah"], :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
169
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
169
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
170
170
  actual.should == expected
171
171
  end
172
172
 
173
173
  it "should handle multiple of same context" do
174
174
  expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => ['Sin','Market'] }
175
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
175
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
176
176
  actual.should == expected
177
177
  end
178
178
 
179
179
  it "should handle no actions" do
180
180
  expected = { :action => "UNKNOWN_ACTION", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
181
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
181
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
182
182
  actual.should == expected
183
183
  end
184
184
 
185
185
  it "should handle actions with the delimiter (and change the delimiter)" do
186
186
  expected = { :action => "address:=search-n", :timestamp => "2010-09-21 23:15:20" }
187
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
187
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
188
188
  actual.should == expected
189
189
 
190
190
  expected = { :action => "address::search==--n", :timestamp => "2010-09-21 23:15:20" }
191
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
191
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
192
192
  actual.should == expected
193
193
  end
194
194
 
195
195
  it "should handle contexts with the delimiter (and change the delimiter)" do
196
196
  expected = { :action => "address", :timestamp => "2010-09-21 23:15:20", :server => "market:eval=-n" }
197
- actual = Appstats::Logger.entry_to_hash("0.19.7 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
197
+ actual = Appstats::Logger.entry_to_hash("0.20.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
198
198
  actual.should == expected
199
199
  end
200
200
 
@@ -203,66 +203,66 @@ module Appstats
203
203
  describe "#entry_to_s" do
204
204
 
205
205
  it "should handle a statistics entry" do
206
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
206
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
207
207
  actual = Appstats::Logger.entry_to_s("address_search")
208
208
  actual.should == expected
209
209
  end
210
210
 
211
211
  it "should handle numbers" do
212
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
212
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
213
213
  actual = Appstats::Logger.entry_to_s(1,:note => 2.2)
214
214
  actual.should == expected
215
215
  end
216
216
 
217
217
  it "should handle default contexts" do
218
218
  Appstats::Logger.default_contexts[:app_name] = "market"
219
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
219
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
220
220
  actual = Appstats::Logger.entry_to_s("address_search")
221
221
  actual.should == expected
222
222
  end
223
223
 
224
224
  it "should handle contexts (and sort them by symbol)" do
225
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
225
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
226
226
  actual = Appstats::Logger.entry_to_s("address_filter", { :server => "Live", :app_name => 'Market' })
227
227
  actual.should == expected
228
228
  end
229
229
 
230
230
  it "should handle actions with the delimiter (and change the delimiter)" do
231
- expected = "0.19.7 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
231
+ expected = "0.20.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
232
232
  actual = Appstats::Logger.entry_to_s("address:=search-n")
233
233
  actual.should == expected
234
234
 
235
- expected = "0.19.7 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
235
+ expected = "0.20.0 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
236
236
  actual = Appstats::Logger.entry_to_s("address::search==--n")
237
237
  actual.should == expected
238
238
  end
239
239
 
240
240
  it "should handle contexts with the delimiter (and change the delimiter)" do
241
- expected = "0.19.7 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
241
+ expected = "0.20.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
242
242
  actual = Appstats::Logger.entry_to_s("address", :server => 'market:eval=-n')
243
243
  actual.should == expected
244
244
  end
245
245
 
246
246
  it "should ignore spaces" do
247
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
247
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
248
248
  actual = Appstats::Logger.entry_to_s("address search")
249
249
  actual.should == expected
250
250
  end
251
251
 
252
252
  it "should convert newlines in action" do
253
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
253
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
254
254
  actual = Appstats::Logger.entry_to_s("address_\nsearch")
255
255
  actual.should == expected
256
256
  end
257
257
 
258
258
  it "should convert newlines in context" do
259
- expected = "0.19.7 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
259
+ expected = "0.20.0 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
260
260
  actual = Appstats::Logger.entry_to_s("address_search",:blah => "some\nlong\nstatement")
261
261
  actual.should == expected
262
262
  end
263
263
 
264
264
  it "should convert newlines based on the delimiter" do
265
- expected = "0.19.7 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
265
+ expected = "0.20.0 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
266
266
  actual = Appstats::Logger.entry_to_s("address:=\nsearch-n")
267
267
  actual.should == expected
268
268
  end
@@ -8,153 +8,153 @@ module Appstats
8
8
  end
9
9
 
10
10
  describe("#initialize") do
11
-
12
- it "should set rules to nil" do
13
- @parser.raw_rules.should == nil
14
- @parser.raw_tokenize.should == nil
15
- @parser.repeating.should == false
16
- @parser.tokenize_regex == nil
17
- @parser.rules.should == []
18
- @parser.tokenize.should == []
19
- @parser.constants.should == []
20
- @parser.constants_no_spaces.should == []
21
- end
22
-
23
- it "should set rules from constructor" do
24
- parser = Parser.new(:rules => ":name or :bust", :tokenize => "a bb c", :repeating => true)
25
- parser.raw_rules.should == ":name or :bust"
26
- parser.raw_tokenize.should == "a bb c"
27
- parser.repeating.should == true
28
- parser.rules.should == [ { :rule => :name, :stop => :constant }, "OR", { :rule => :bust, :stop => :end} ]
29
- parser.tokenize.should == ["\\s+A","\\s+BB","\\s+C"]
30
- parser.tokenize_no_spaces.should == ["A","BB","C"]
31
- parser.constants.should == ["\\s+OR"]
32
- parser.constants_no_spaces.should == ["OR"]
33
- end
34
-
35
- it "should espace tokens as required" do
36
- parser = Parser.new(:tokenize => "( ) abc |")
37
- parser.tokenize.should == ['\(','\)','\s+ABC','\|']
38
- parser.tokenize_regex.should == '\(|\)|\s+ABC|\|'
39
- parser.tokenize_no_spaces.should == ['\(','\)','ABC','\|']
40
- parser.tokenize_regex_no_spaces.should == '\(|\)|ABC|\|'
41
- end
42
-
43
- end
11
+
12
+ it "should set rules to nil" do
13
+ @parser.raw_rules.should == nil
14
+ @parser.raw_tokenize.should == nil
15
+ @parser.repeating.should == false
16
+ @parser.tokenize_regex == nil
17
+ @parser.rules.should == []
18
+ @parser.tokenize.should == []
19
+ @parser.constants.should == []
20
+ @parser.constants_no_spaces.should == []
21
+ end
22
+
23
+ it "should set rules from constructor" do
24
+ parser = Parser.new(:rules => ":name or :bust", :tokenize => "a bb c", :repeating => true)
25
+ parser.raw_rules.should == ":name or :bust"
26
+ parser.raw_tokenize.should == "a bb c"
27
+ parser.repeating.should == true
28
+ parser.rules.should == [ { :rule => :name, :stop => :constant }, "OR", { :rule => :bust, :stop => :end} ]
29
+ parser.tokenize.should == ["\\s+A(\\s|$)","\\s+BB(\\s|$)","\\s+C(\\s|$)"]
30
+ parser.tokenize_no_spaces.should == ["A","BB","C"]
31
+ parser.constants.should == ["\\s+OR(\\s|$)"]
32
+ parser.constants_no_spaces.should == ["OR"]
33
+ end
44
34
 
35
+ it "should espace tokens as required" do
36
+ parser = Parser.new(:tokenize => "( ) abc |")
37
+ parser.tokenize.should == ['\(','\)','\s+ABC(\s|$)','\|']
38
+ parser.tokenize_regex.should == '\(|\)|\s+ABC(\s|$)|\|'
39
+ parser.tokenize_no_spaces.should == ['\(','\)','ABC','\|']
40
+ parser.tokenize_regex_no_spaces.should == '\(|\)|ABC|\|'
41
+ end
45
42
 
46
- describe "#rules" do
47
-
48
- it "should end on constant if tokens present" do
49
- Parser.new(:rules => ":name", :tokenize => ")").rules.should == [ { :rule => :name, :stop => :end } ]
50
- end
51
-
43
+ end
52
44
 
53
- it "should handle one variable" do
54
- Parser.new(:rules => ":name").rules.should == [ { :rule => :name, :stop => :end } ]
55
- end
56
-
57
- it "should handle many variables" do
58
- Parser.new(:rules => ":name :date").rules.should == [ { :rule => :name, :stop => :space }, { :rule => :date, :stop => :end } ]
59
- end
60
-
61
- it "should deal with colons" do
62
- Parser.new(:rules => ":name : :date").rules.should == [ { :rule => :name, :stop => :constant }, ":", { :rule => :date, :stop => :end } ]
63
- end
64
-
65
- it "should deal with constant" do
66
- Parser.new(:rules => "blah").rules.should == ["BLAH"]
67
- end
68
-
69
- it "should deal with constant and variables" do
70
- Parser.new(:rules => ":name blah :date").rules.should == [ { :rule => :name, :stop => :constant }, "BLAH", { :rule => :date, :stop => :end } ]
71
- end
72
-
73
- it "should deal with multiple constants and variables" do
74
- Parser.new(:rules => ":name blah more blah :date").rules.should == [ { :rule => :name, :stop => :constant }, "BLAH", "MORE", "BLAH", { :rule => :date, :stop => :end } ]
75
- end
76
45
 
77
- end
46
+ describe "#rules" do
78
47
 
79
- describe "#constants" do
80
-
81
- it "should be empty if only variables" do
82
- Parser.new(:rules => ":name :blah").constants.should == [ ]
83
- end
84
-
85
- it "should track all constants" do
86
- Parser.new(:rules => ":name : :date").constants.should == [ ":" ]
87
- end
88
-
89
- it "should upper case constants" do
90
- Parser.new(:rules => "blah").constants.should == ["\\s+BLAH"]
91
- end
92
-
93
- it "should deal with multiple constants" do
94
- Parser.new(:rules => ":name = :blah and :moreblah").constants.should == ["=","\\s+AND"]
95
- end
96
-
97
- end
98
-
99
- describe "#constants_no_spaces" do
48
+ it "should end on constant if tokens present" do
49
+ Parser.new(:rules => ":name", :tokenize => ")").rules.should == [ { :rule => :name, :stop => :end } ]
50
+ end
51
+
52
+
53
+ it "should handle one variable" do
54
+ Parser.new(:rules => ":name").rules.should == [ { :rule => :name, :stop => :end } ]
55
+ end
56
+
57
+ it "should handle many variables" do
58
+ Parser.new(:rules => ":name :date").rules.should == [ { :rule => :name, :stop => :space }, { :rule => :date, :stop => :end } ]
59
+ end
60
+
61
+ it "should deal with colons" do
62
+ Parser.new(:rules => ":name : :date").rules.should == [ { :rule => :name, :stop => :constant }, ":", { :rule => :date, :stop => :end } ]
63
+ end
64
+
65
+ it "should deal with constant" do
66
+ Parser.new(:rules => "blah").rules.should == ["BLAH"]
67
+ end
68
+
69
+ it "should deal with constant and variables" do
70
+ Parser.new(:rules => ":name blah :date").rules.should == [ { :rule => :name, :stop => :constant }, "BLAH", { :rule => :date, :stop => :end } ]
71
+ end
72
+
73
+ it "should deal with multiple constants and variables" do
74
+ Parser.new(:rules => ":name blah more blah :date").rules.should == [ { :rule => :name, :stop => :constant }, "BLAH", "MORE", "BLAH", { :rule => :date, :stop => :end } ]
75
+ end
76
+
77
+ end
100
78
 
101
- it "should be empty if only variables" do
102
- Parser.new(:rules => ":name :blah").constants_no_spaces.should == [ ]
103
- end
104
-
105
- it "should track all constants" do
106
- Parser.new(:rules => ":name : :date").constants_no_spaces.should == [ ":" ]
107
- end
108
-
109
- it "should upper case constants" do
110
- Parser.new(:rules => "blah").constants_no_spaces.should == ["BLAH"]
111
- end
112
-
113
- it "should deal with multiple constants" do
114
- Parser.new(:rules => ":name = :blah and :moreblah").constants_no_spaces.should == ["=","AND"]
115
- end
116
-
117
- end
79
+ describe "#constants" do
80
+
81
+ it "should be empty if only variables" do
82
+ Parser.new(:rules => ":name :blah").constants.should == [ ]
83
+ end
118
84
 
119
- describe "#parse_constant" do
120
-
121
- it "should handle nil" do
122
- Parser.parse_constant(nil,nil).should == [nil,nil]
123
- Parser.parse_constant("",nil).should == [nil,nil]
124
- end
125
-
126
- it "should find the constant" do
127
- Parser.parse_constant("= blah blah more blah ","=").should == ["=","blah blah more blah"]
128
- end
129
-
130
- it "should find the constants with multiple characters" do
131
- Parser.parse_constant("hey blah blah more blah ","hey").should == ["hey","blah blah more blah"]
132
- end
133
-
134
- it "should return nil if not found" do
135
- Parser.parse_constant("blah blah more blah ","=").should == [nil,"blah blah more blah"]
136
- end
137
-
138
- it "should be case insensitive" do
139
- Parser.parse_constant(" blah stuff on more blah stuff ","blah").should == ["blah","stuff on more blah stuff"]
140
- Parser.parse_constant(" BLAH stuff on more blah stuff ","blah").should == ["BLAH","stuff on more blah stuff"]
141
- Parser.parse_constant(" blah stuff on more blah stuff ","BLAH").should == ["blah","stuff on more blah stuff"]
142
- end
143
-
144
- it "should only find the first instance" do
145
- Parser.parse_constant("one == two","==").should == [nil,"one == two"]
146
- end
85
+ it "should track all constants" do
86
+ Parser.new(:rules => ":name : :date").constants.should == [ ":" ]
87
+ end
88
+
89
+ it "should upper case constants" do
90
+ Parser.new(:rules => "blah").constants.should == ["\\s+BLAH(\\s|$)"]
91
+ end
92
+
93
+ it "should deal with multiple constants" do
94
+ Parser.new(:rules => ":name = :blah and :moreblah").constants.should == ["=","\\s+AND(\\s|$)"]
95
+ end
96
+
97
+ end
98
+
99
+ describe "#constants_no_spaces" do
100
+
101
+ it "should be empty if only variables" do
102
+ Parser.new(:rules => ":name :blah").constants_no_spaces.should == [ ]
103
+ end
104
+
105
+ it "should track all constants" do
106
+ Parser.new(:rules => ":name : :date").constants_no_spaces.should == [ ":" ]
107
+ end
108
+
109
+ it "should upper case constants" do
110
+ Parser.new(:rules => "blah").constants_no_spaces.should == ["BLAH"]
111
+ end
112
+
113
+ it "should deal with multiple constants" do
114
+ Parser.new(:rules => ":name = :blah and :moreblah").constants_no_spaces.should == ["=","AND"]
115
+ end
116
+
117
+ end
147
118
 
148
- end
119
+ describe "#parse_constant" do
120
+
121
+ it "should handle nil" do
122
+ Parser.parse_constant(nil,nil).should == [nil,nil]
123
+ Parser.parse_constant("",nil).should == [nil,nil]
124
+ end
125
+
126
+ it "should find the constant" do
127
+ Parser.parse_constant("= blah blah more blah ","=").should == ["=","blah blah more blah"]
128
+ end
129
+
130
+ it "should find the constants with multiple characters" do
131
+ Parser.parse_constant("hey blah blah more blah ","hey").should == ["hey","blah blah more blah"]
132
+ end
133
+
134
+ it "should return nil if not found" do
135
+ Parser.parse_constant("blah blah more blah ","=").should == [nil,"blah blah more blah"]
136
+ end
137
+
138
+ it "should be case insensitive" do
139
+ Parser.parse_constant(" blah stuff on more blah stuff ","blah").should == ["blah","stuff on more blah stuff"]
140
+ Parser.parse_constant(" BLAH stuff on more blah stuff ","blah").should == ["BLAH","stuff on more blah stuff"]
141
+ Parser.parse_constant(" blah stuff on more blah stuff ","BLAH").should == ["blah","stuff on more blah stuff"]
142
+ end
149
143
 
150
- describe "#parse_word" do
144
+ it "should only find the first instance" do
145
+ Parser.parse_constant("one == two","==").should == [nil,"one == two"]
146
+ end
147
+
148
+ end
151
149
 
152
- it "should handle nil" do
153
- @parser.parse_word(nil,nil).should == [nil,nil]
154
- @parser.parse_word("",nil).should == [nil,nil]
155
- end
156
-
157
- it "should look for global tokens" do
150
+ describe "#parse_word" do
151
+
152
+ it "should handle nil" do
153
+ @parser.parse_word(nil,nil).should == [nil,nil]
154
+ @parser.parse_word("",nil).should == [nil,nil]
155
+ end
156
+
157
+ it "should look for global tokens" do
158
158
  parser = Parser.new(:tokenize => "xx")
159
159
  parser.parse_word("blah xx",:end).should == ["blah","xx"]
160
160
  parser.parse_word("blah xx stop","stop").should == ["blah","xx stop"]
@@ -259,6 +259,29 @@ module Appstats
259
259
 
260
260
  end
261
261
 
262
+ describe "#alpha?" do
263
+
264
+ it "should be false for nil" do
265
+ Parser.alpha?(nil).should == false
266
+ end
267
+
268
+ it "should be false for empty string" do
269
+ Parser.alpha?('').should == false
270
+ end
271
+
272
+ it "should be false for non alpha string" do
273
+ Parser.alpha?('1abc').should == false
274
+ Parser.alpha?('abc2').should == false
275
+ Parser.alpha?('abc2def').should == false
276
+ end
277
+
278
+ it "should be true for alpha string" do
279
+ Parser.alpha?('a').should == true
280
+ Parser.alpha?('abc').should == true
281
+ end
282
+
283
+ end
284
+
262
285
  describe "#parse" do
263
286
 
264
287
 
@@ -339,6 +362,12 @@ module Appstats
339
362
  parser.raw_results.should == [ "(", { :one => "blaa"}, "aa", "a1", { :two => "bla1"}, ")" ]
340
363
  end
341
364
 
365
+ it "should handle alpha constants as requiring spaces" do
366
+ parser = Appstats::Parser.new(:rules => ":one group :two")
367
+ parser.parse("group_by group aha")
368
+ parser.raw_results.should == [ { :one => "group_by"}, "group", { :two => "aha"} ]
369
+ end
370
+
342
371
 
343
372
  describe "real examples" do
344
373
 
@@ -367,6 +396,13 @@ module Appstats
367
396
  parser.parse("# buyer-address-lookup last month").should == true
368
397
  parser.raw_results.should == [{:operation=>"#"}, {:action=>"buyer-address-lookup"}, {:host=>nil}, {:contexts=>nil}, {:date=>"last month"}]
369
398
  end
399
+
400
+ it "should handle group_by" do
401
+ parser = Appstats::Parser.new(:rules => ":operation :action :date on :host where :contexts group by :group_by")
402
+ parser.parse("# appstats_queries where action = abc AND contexts = 'def' || group_by like 'hik'").should == true
403
+ parser.results.should == {:operation => "#", :action => "appstats_queries", :date => nil, :host => nil, :group_by => nil, :contexts => "action = abc AND contexts = 'def' || group_by like 'hik'" }
404
+ end
405
+
370
406
 
371
407
  end
372
408
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appstats
3
3
  version: !ruby/object:Gem::Version
4
- hash: 93
4
+ hash: 79
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 19
9
- - 7
10
- version: 0.19.7
8
+ - 20
9
+ - 0
10
+ version: 0.20.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Forward
@@ -181,10 +181,13 @@ files:
181
181
  - db/migrations/20110311214833_add_appstats_results_db_connection.rb
182
182
  - db/migrations/20110318203339_add_appstats_results_latest_flag.rb
183
183
  - db/migrations/20110321154125_add_appstats_results_query_duration_in_seconds.rb
184
+ - db/migrations/20110330171745_create_appstats_action_contexts.rb
184
185
  - db/schema.rb
185
186
  - lib/appstats.rb
186
187
  - lib/appstats/action.rb
188
+ - lib/appstats/action_context_key.rb
187
189
  - lib/appstats/acts_as_appstatsable.rb
190
+ - lib/appstats/appstats_query.rb
188
191
  - lib/appstats/ci.rake
189
192
  - lib/appstats/code_injections.rb
190
193
  - lib/appstats/context.rb
@@ -227,8 +230,10 @@ files:
227
230
  - script/console
228
231
  - script/destroy
229
232
  - script/generate
233
+ - spec/action_context_key_spec.rb
230
234
  - spec/action_spec.rb
231
235
  - spec/acts_as_appstatsble_spec.rb
236
+ - spec/appstats_query_spec.rb
232
237
  - spec/appstats_spec.rb
233
238
  - spec/context_key_spec.rb
234
239
  - spec/context_spec.rb
@@ -282,8 +287,10 @@ signing_key:
282
287
  specification_version: 3
283
288
  summary: Provide usage statistics about how your application is being used
284
289
  test_files:
290
+ - spec/action_context_key_spec.rb
285
291
  - spec/action_spec.rb
286
292
  - spec/acts_as_appstatsble_spec.rb
293
+ - spec/appstats_query_spec.rb
287
294
  - spec/appstats_spec.rb
288
295
  - spec/context_key_spec.rb
289
296
  - spec/context_spec.rb