kmts 2.0.0

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