kmts 2.0.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.
Files changed (72) hide show
  1. data/.gitignore +5 -0
  2. data/CHANGELOG +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +29 -0
  5. data/LICENSE +202 -0
  6. data/README.md +64 -0
  7. data/README.rdoc +14 -0
  8. data/Rakefile +5 -0
  9. data/bin/km_send +35 -0
  10. data/doc/Accept.html +546 -0
  11. data/doc/Gemfile.html +110 -0
  12. data/doc/Hash.html +283 -0
  13. data/doc/Helper.html +318 -0
  14. data/doc/KMError.html +159 -0
  15. data/doc/KMTS.html +493 -0
  16. data/doc/KMTS/IdentError.html +159 -0
  17. data/doc/KMTS/InitError.html +159 -0
  18. data/doc/KMTS/SaaS.html +451 -0
  19. data/doc/Object.html +211 -0
  20. data/doc/README_rdoc.html +122 -0
  21. data/doc/Rakefile.html +111 -0
  22. data/doc/String.html +244 -0
  23. data/doc/bin/km_send.html +54 -0
  24. data/doc/created.rid +15 -0
  25. data/doc/images/brick.png +0 -0
  26. data/doc/images/brick_link.png +0 -0
  27. data/doc/images/bug.png +0 -0
  28. data/doc/images/bullet_black.png +0 -0
  29. data/doc/images/bullet_toggle_minus.png +0 -0
  30. data/doc/images/bullet_toggle_plus.png +0 -0
  31. data/doc/images/date.png +0 -0
  32. data/doc/images/find.png +0 -0
  33. data/doc/images/loadingAnimation.gif +0 -0
  34. data/doc/images/macFFBgHack.png +0 -0
  35. data/doc/images/package.png +0 -0
  36. data/doc/images/page_green.png +0 -0
  37. data/doc/images/page_white_text.png +0 -0
  38. data/doc/images/page_white_width.png +0 -0
  39. data/doc/images/plugin.png +0 -0
  40. data/doc/images/ruby.png +0 -0
  41. data/doc/images/tag_green.png +0 -0
  42. data/doc/images/wrench.png +0 -0
  43. data/doc/images/wrench_orange.png +0 -0
  44. data/doc/images/zoom.png +0 -0
  45. data/doc/index.html +142 -0
  46. data/doc/js/darkfish.js +116 -0
  47. data/doc/js/jquery.js +32 -0
  48. data/doc/js/quicksearch.js +114 -0
  49. data/doc/js/thickbox-compressed.js +10 -0
  50. data/doc/lib/km/saas_rb.html +54 -0
  51. data/doc/lib/km/version_rb.html +52 -0
  52. data/doc/lib/km_rb.html +60 -0
  53. data/doc/rdoc.css +730 -0
  54. data/doc/spec/accept_rb.html +62 -0
  55. data/doc/spec/km_old_rb.html +54 -0
  56. data/doc/spec/km_saas_spec_rb.html +56 -0
  57. data/doc/spec/km_send_spec_rb.html +54 -0
  58. data/doc/spec/km_spec_rb.html +54 -0
  59. data/doc/spec/setup_rb.html +60 -0
  60. data/doc/spec/watchr_rb.html +52 -0
  61. data/kmts.gemspec +26 -0
  62. data/lib/kmts.rb +245 -0
  63. data/lib/kmts/saas.rb +39 -0
  64. data/lib/kmts/version.rb +3 -0
  65. data/spec/accept.rb +91 -0
  66. data/spec/km_old.rb +105 -0
  67. data/spec/km_saas_spec.rb +107 -0
  68. data/spec/km_send_spec.rb +98 -0
  69. data/spec/km_spec.rb +175 -0
  70. data/spec/setup.rb +77 -0
  71. data/spec/watchr.rb +3 -0
  72. metadata +190 -0
@@ -0,0 +1,39 @@
1
+ require 'kmts'
2
+ class KMTS
3
+ module SaaS
4
+ def signed_up(id, plan=nil, props = {})
5
+ props['Plan Name'] = plan unless plan.to_s.empty?
6
+ record id, 'Signed Up', props
7
+ end
8
+ alias signedup signed_up
9
+
10
+ def upgraded(id, plan=nil, props = {})
11
+ props['Plan Name'] = plan unless plan.to_s.empty?
12
+ record id, 'Upgraded', props
13
+ end
14
+
15
+ def downgraded(id, plan=nil, props = {})
16
+ props['Plan Name'] = plan unless plan.to_s.empty?
17
+ record id, 'Downgraded', props
18
+ end
19
+
20
+ def billed(id, amount=nil, description=nil, props={})
21
+ props['Billing Amount'] = amount unless amount.to_s.empty?
22
+ props['Billing Description'] = description unless description.to_s.empty?
23
+ record id, 'Billed', props
24
+ end
25
+
26
+ def canceled(id, props={})
27
+ record id, 'Canceled', props
28
+ end
29
+ alias cancelled canceled
30
+
31
+ def visited_site(id, url=nil, referrer=nil, props={})
32
+ props['URL'] = url unless url.to_s.empty?
33
+ props['Referrer'] = referrer unless referrer.to_s.empty?
34
+ record id, 'Visited Site', props
35
+ end
36
+ # ------------------------------------------------------------------------
37
+ end
38
+ end
39
+ KMTS.send :extend, KMTS::SaaS
@@ -0,0 +1,3 @@
1
+ class KMTS
2
+ VERSION = "2.0.0"
3
+ end
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ require 'socket'
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'uri'
6
+ require 'cgi'
7
+
8
+ # a library to accept connections as a server, and send back what it received on request.
9
+
10
+ class Accept
11
+ attr_accessor :server, :session
12
+ attr_reader :opts
13
+ URI_REXEGP = /^\s*(\w+)\s+([^ ]*)\s+(.*)$/
14
+ def initialize(args = {})
15
+ opts = { :port => 9292, :debug => false }
16
+ opts.update(args)
17
+
18
+ puts "Starting up server on port #{opts[:port]} ..."
19
+ @opts = opts
20
+ @server = TCPServer.new(opts[:port])
21
+ @@input_history = []
22
+ @handle = Thread.start do
23
+ loop do
24
+ Thread.start(@server.accept) do |client|
25
+ # puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"
26
+ # session.puts "Server: Connection from #{session.peeraddr[2]}\n"
27
+ handle_input(client)
28
+ client.close
29
+ end
30
+ end
31
+ end
32
+ end
33
+ def input_history
34
+ @@input_history
35
+ end
36
+ def wait
37
+ @handle.join
38
+ end
39
+
40
+ def handle_input(client)
41
+ input = client.gets
42
+ if input
43
+ puts "received: #{input.inspect}" if opts[:debug]
44
+ case input
45
+ when /clear/
46
+ clear
47
+ when /history/
48
+ client.puts input_history.to_json
49
+ when /exit/
50
+ begin
51
+ close
52
+ rescue Exception
53
+ end
54
+ return
55
+ when /^\s*(GET|POST|PUT|DELETE)\s+([^ ]*)\s+(.*)$/
56
+ @@input_history << parse_input(input)
57
+ client.puts "HTTP/1.1 200 OK"
58
+ else
59
+ @@input_history << input.chomp
60
+ end
61
+ end
62
+ end
63
+ def parse_input(input)
64
+ data = {}
65
+ data[:raw] = input.chomp
66
+ (method,uri,http) = input.scan(/^\s*(\w+)\s+([^ ]*)\s+(.*)$/).flatten
67
+
68
+ data[:method] = method
69
+ data[:http] = http.chomp
70
+ data[:uri] = uri
71
+ u = URI(uri)
72
+ data[:path] = u.path
73
+ data[:query] = CGI.parse(u.query)
74
+ return data
75
+ end
76
+ def close
77
+ session = nil
78
+ server.close
79
+ end
80
+ # clear history
81
+ def clear
82
+ @@input_history.clear
83
+ end
84
+ end
85
+ __END__
86
+ % ruby -r './lib/ruby/accept.rb' -e 'Accept.new(:debug => true, :port => 9292).wait'
87
+ Starting up server on port 9292 ...
88
+
89
+ echo rain | nc localhost 9292
90
+ % echo history | nc localhost 9292
91
+ ["rain"]
@@ -0,0 +1,105 @@
1
+ require 'setup'
2
+
3
+ describe KMTS do
4
+ attr_accessor :send_query, :log
5
+ before do
6
+ @send_query = []
7
+ @log = []
8
+ KMTS.stub(:send_query).and_return { |*args| send_query << args }
9
+ KMTS.stub(:log).and_return { |*args| log << Hash[*args] }
10
+ time = Time.at 1234567890
11
+ Time.stub!(:now).and_return(time)
12
+ KMTS.reset
13
+ end
14
+ context "initialization" do
15
+ it "should not record without initialization" do
16
+ KMTS::record 'My Action'
17
+ log.first[:error].should =~ /Need to initialize first \(KMTS::init <your_key>\)/
18
+ end
19
+ it "should not set initialization" do
20
+ KMTS::set :day => 'friday'
21
+ log.first[:error].should =~ /Need to initialize first \(KMTS::init <your_key>\)/
22
+ end
23
+ end
24
+ context "identification" do
25
+ before do
26
+ KMTS::init 'KM_KEY'
27
+ end
28
+ it "should not record without identification" do
29
+ KMTS::record 'My Action'
30
+ log.first[:error].should include("Need to identify first (KMTS::identify <user>)")
31
+ end
32
+ it "should set without identification" do
33
+ KMTS::record 'My Action'
34
+ log.first[:error].should include("Need to identify first (KMTS::identify <user>)")
35
+ end
36
+
37
+ context "aliasing" do
38
+ it "shouldn't fail on alias without identifying" do
39
+ KMTS::alias 'peter','joe' # Alias "bob" to "robert"
40
+ send_query.first.first.should have_query_string("/a?_n=joe&_p=peter&_k=KM_KEY&_t=1234567890")
41
+ end
42
+ end
43
+ end
44
+
45
+ context "events" do
46
+ before do
47
+ KMTS::init 'KM_KEY'
48
+ KMTS::identify 'bob'
49
+ end
50
+ it "should record an action with no specific props" do
51
+ KMTS::record 'My Action'
52
+ send_query.first.first.should have_query_string("/e?_n=My+Action&_p=bob&_k=KM_KEY&_t=1234567890")
53
+ end
54
+ it "should record an action with properties" do
55
+ KMTS::record 'Signup', 'age' => 26
56
+ send_query.first.first.should have_query_string("/e?age=26&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
57
+ end
58
+ it "should reocrd properties with spaces in key and value" do
59
+ KMTS::record 'Signup', 'age' => 26, 'city of residence' => 'eug ene'
60
+ send_query.first.first.should have_query_string("/e?age=26&city+of+residence=eug+ene&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
61
+ end
62
+ it "should not over-write special keys" do
63
+ KMTS::record 'Signup', 'age' => 26, '_p' => 'billybob', '_k' => 'foo', '_n' => 'something else'
64
+ send_query.first.first.should have_query_string("/e?age=26&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
65
+ end
66
+ it "should not over-write special keys with symbols" do
67
+ KMTS::record 'Signup', 'age' => 26, '_p' => 'billybob', :'_k' => 'foo', :'_n' => 'something else'
68
+ send_query.first.first.should have_query_string("/e?age=26&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
69
+ end
70
+ it "should work with properties with @" do
71
+ KMTS::record 'Signup', 'email' => 'test@blah.com', '_p' => 'billybob', '_k' => 'foo', '_n' => 'something else'
72
+ send_query.first.first.should have_query_string("/e?email=test%40blah.com&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
73
+ end
74
+ it "should work with just set" do
75
+ KMTS::record 'age' => 26
76
+ send_query.first.first.should have_query_string("/s?age=26&_p=bob&_k=KM_KEY&_t=1234567890")
77
+ end
78
+ it "should record ok with multiple calls" do
79
+ KMTS::record 'Signup', 'age' => 26
80
+ KMTS::record 'Signup', 'age' => 36
81
+ send_query.first.first.should have_query_string("/e?age=26&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
82
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
83
+ end
84
+ it "shouldn't store the key anywhere" do
85
+ KMTS::init 'KM_OTHER'
86
+ KMTS::alias 'truman','harry' # Alias "bob" to "robert"
87
+ send_query.first.first.should have_query_string("/a?_n=harry&_p=truman&_k=KM_OTHER&_t=1234567890")
88
+ end
89
+ it "should override the time if defined" do
90
+ KMTS::record 'Signup', 'age' => 36, '_t' => 1234567891
91
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567891&_d=1")
92
+ end
93
+ it "should work with either symbols or strings" do
94
+ KMTS::record :Signup, :age => 36, :_t => 1234567891
95
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567891&_d=1")
96
+ end
97
+ end
98
+
99
+ it "should test cron" do
100
+ pending
101
+ end
102
+ it "should send logged queries" do
103
+ pending
104
+ end
105
+ end
@@ -0,0 +1,107 @@
1
+ require 'setup'
2
+ require 'kmts/saas'
3
+ describe KMTS do
4
+ before do
5
+ KMTS::reset
6
+ now = Time.now
7
+ Time.stub!(:now).and_return(now)
8
+ FileUtils.rm_f KMTS::log_name(:error)
9
+ FileUtils.rm_f KMTS::log_name(:query)
10
+ Helper.clear
11
+ end
12
+
13
+ describe "should record events" do
14
+ before do
15
+ KMTS::init 'KM_KEY', :log_dir => __('log'), :host => '127.0.0.1:9292'
16
+ end
17
+ context "plain usage" do
18
+ it "records a signup event" do
19
+ KMTS.signed_up 'bob', 'Premium'
20
+ sleep 0.1
21
+ res = Helper.accept(:history).first.indifferent
22
+ res[:path].should == '/e'
23
+ res[:query]['_n'].first.should == 'Signed Up'
24
+ res[:query]['Plan Name'].first.should == 'Premium'
25
+ end
26
+ it "records an upgraded event" do
27
+ KMTS.upgraded 'bob', 'Unlimited'
28
+ sleep 0.1
29
+ res = Helper.accept(:history).first.indifferent
30
+ res[:path].should == '/e'
31
+ res[:query]['_n'].first.should == 'Upgraded'
32
+ res[:query]['Plan Name'].first.should == 'Unlimited'
33
+ end
34
+ it "records a downgraded event" do
35
+ KMTS.downgraded 'bob', 'Free'
36
+ sleep 0.1
37
+ res = Helper.accept(:history).first.indifferent
38
+ res[:path].should == '/e'
39
+ res[:query]['_n'].first.should == 'Downgraded'
40
+ res[:query]['Plan Name'].first.should == 'Free'
41
+ end
42
+ it "records a billed event" do
43
+ KMTS.billed 'bob', 32, 'Upgraded'
44
+ sleep 0.1
45
+ res = Helper.accept(:history).first.indifferent
46
+ res[:path].should == '/e'
47
+ res[:query]['_n'].first.should == 'Billed'
48
+ res[:query]['Billing Amount'].first.should == '32'
49
+ res[:query]['Billing Description'].first.should == 'Upgraded'
50
+ end
51
+ it "records a canceled event" do
52
+ KMTS.canceled 'bob'
53
+ sleep 0.1
54
+ res = Helper.accept(:history).first.indifferent
55
+ res[:path].should == '/e'
56
+ res[:query]['_n'].first.should == 'Canceled'
57
+ end
58
+ it "records a visited site event" do
59
+ KMTS.visited_site 'bob', 'http://duckduckgo.com', 'http://kissmetrics.com'
60
+ sleep 0.1
61
+ res = Helper.accept(:history).first.indifferent
62
+ res[:path].should == '/e'
63
+ res[:query]['_n'].first.should == 'Visited Site'
64
+ res[:query]['URL'].first.should == 'http://duckduckgo.com'
65
+ res[:query]['Referrer'].first.should == 'http://kissmetrics.com'
66
+ end
67
+ end
68
+ context "usage with props" do
69
+ it "records a signup event" do
70
+ KMTS.signed_up 'bob', 'Premium', :foo => 'bar'
71
+ sleep 0.1
72
+ res = Helper.accept(:history).first.indifferent
73
+ res[:query]['foo'].first.should == 'bar'
74
+ end
75
+ it "records an upgraded event" do
76
+ KMTS.upgraded 'bob', 'Unlimited', :foo => 'bar'
77
+ sleep 0.1
78
+ res = Helper.accept(:history).first.indifferent
79
+ res[:query]['foo'].first.should == 'bar'
80
+ end
81
+ it "records a downgraded event" do
82
+ KMTS.downgraded 'bob', 'Free', :foo => 'bar'
83
+ sleep 0.1
84
+ res = Helper.accept(:history).first.indifferent
85
+ res[:query]['foo'].first.should == 'bar'
86
+ end
87
+ it "records a billed event" do
88
+ KMTS.billed 'bob', 32, 'Upgraded', :foo => 'bar'
89
+ sleep 0.1
90
+ res = Helper.accept(:history).first.indifferent
91
+ res[:query]['foo'].first.should == 'bar'
92
+ end
93
+ it "records a canceled event" do
94
+ KMTS.canceled 'bob', :foo => 'bar'
95
+ sleep 0.1
96
+ res = Helper.accept(:history).first.indifferent
97
+ res[:query]['foo'].first.should == 'bar'
98
+ end
99
+ it "records a visited site event" do
100
+ KMTS.visited_site 'bob', 'http://duckduckgo.com', 'http://kissmetrics.com', :foo => 'bar'
101
+ sleep 0.1
102
+ res = Helper.accept(:history).first.indifferent
103
+ res[:query]['foo'].first.should == 'bar'
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,98 @@
1
+ require 'setup'
2
+
3
+ describe 'km_send' do
4
+ context "using cron for sending logs" do
5
+ before do
6
+ now = Time.now
7
+ Time.stub!(:now).and_return(now)
8
+ Dir.glob(__('log','*')).each do |file|
9
+ FileUtils.rm file
10
+ end
11
+ KMTS.reset
12
+ Helper.clear
13
+ end
14
+ context "with default environment" do
15
+ before do
16
+ KMTS::init 'KM_KEY', :log_dir => __('log'), :host => '127.0.0.1:9292', :use_cron => true
17
+ end
18
+ it "should test commandline version" do
19
+ KMTS::record 'bob', 'Signup', 'age' => 26
20
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
21
+ sleep 0.1
22
+ res = Helper.accept(:history).first.indifferent
23
+ res[:path].should == '/e'
24
+ res[:query]['_k'].first.should == 'KM_KEY'
25
+ res[:query]['_p'].first.should == 'bob'
26
+ res[:query]['_n'].first.should == 'Signup'
27
+ res[:query]['_t'].first.should == Time.now.to_i.to_s
28
+ res[:query]['age'].first.should == '26'
29
+ end
30
+ it "should send from query_log" do
31
+ write_log :query, "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26"
32
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
33
+ sleep 0.1
34
+ res = Helper.accept(:history).first.indifferent
35
+ res[:path].should == '/e'
36
+ res[:query]['_k'].first.should == 'KM_KEY'
37
+ res[:query]['_p'].first.should == 'bob'
38
+ res[:query]['_n'].first.should == 'Signup'
39
+ res[:query]['_t'].first.should == '1297105499'
40
+ res[:query]['age'].first.should == '26'
41
+ end
42
+ it "should send from query_log_old" do
43
+ write_log :query_old, "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26"
44
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
45
+ sleep 0.1
46
+ res = Helper.accept(:history).first.indifferent
47
+ res[:path].should == '/e'
48
+ res[:query]['_k'].first.should == 'KM_KEY'
49
+ res[:query]['_p'].first.should == 'bob'
50
+ res[:query]['_n'].first.should == 'Signup'
51
+ res[:query]['_t'].first.should == '1297105499'
52
+ res[:query]['age'].first.should == '26'
53
+ end
54
+ it "should send from both query_log and query_log_old" do
55
+ File.open(__('log/kissmetrics_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=27" }
56
+ File.open(__('log/kissmetrics_production_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26" }
57
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
58
+ sleep 0.1
59
+ res = Helper.accept(:history).first.indifferent
60
+ res[:path].should == '/e'
61
+ res[:query]['_k'].first.should == 'KM_KEY'
62
+ res[:query]['_p'].first.should == 'bob'
63
+ res[:query]['_n'].first.should == 'Signup'
64
+ res[:query]['_t'].first.should == '1297105499'
65
+ res[:query]['age'].first.should == '27'
66
+ Helper.clear
67
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
68
+ sleep 0.1
69
+ res = Helper.accept(:history).first.indifferent
70
+ res[:path].should == '/e'
71
+ res[:query]['_k'].first.should == 'KM_KEY'
72
+ res[:query]['_p'].first.should == 'bob'
73
+ res[:query]['_n'].first.should == 'Signup'
74
+ res[:query]['_t'].first.should == '1297105499'
75
+ res[:query]['age'].first.should == '26'
76
+ end
77
+ it "sends unless dryrun is specified" do
78
+ File.open(__('log/kissmetrics_alpha_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26" }
79
+ `bundle exec km_send -e alpha #{__('log/')} 127.0.0.1:9292`
80
+ sleep 0.1
81
+ res = Helper.accept(:history).first.should_not be_nil
82
+ end
83
+ end
84
+ it "should send from diff environment when force flag is used" do
85
+ KMTS::init 'KM_KEY', :log_dir => __('log'), :host => '127.0.0.1:9292', :use_cron => true, :env => 'development', :force => true
86
+ KMTS::record 'bob', 'Signup', 'age' => 26
87
+ `bundle exec km_send -f -e development #{__('log/')} 127.0.0.1:9292`
88
+ sleep 0.1
89
+ res = Helper.accept(:history).first.indifferent
90
+ res[:path].should == '/e'
91
+ res[:query]['_k'].first.should == 'KM_KEY'
92
+ res[:query]['_p'].first.should == 'bob'
93
+ res[:query]['_n'].first.should == 'Signup'
94
+ res[:query]['_t'].first.should == Time.now.to_i.to_s
95
+ res[:query]['age'].first.should == '26'
96
+ end
97
+ end
98
+ end