snogmetrics 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.document +5 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +20 -0
  5. data/README.mdown +50 -0
  6. data/Rakefile +44 -0
  7. data/example/snoggy/.gitignore +1 -0
  8. data/example/snoggy/README.mdown +7 -0
  9. data/example/snoggy/Rakefile +10 -0
  10. data/example/snoggy/app/controllers/application_controller.rb +2 -0
  11. data/example/snoggy/app/controllers/snogs_controller.rb +9 -0
  12. data/example/snoggy/app/views/layouts/application.html.erb +12 -0
  13. data/example/snoggy/app/views/snogs/new.html.erb +11 -0
  14. data/example/snoggy/app/views/snogs/thank_you.html.erb +1 -0
  15. data/example/snoggy/config/boot.rb +110 -0
  16. data/example/snoggy/config/environment.rb +13 -0
  17. data/example/snoggy/config/environments/development.rb +6 -0
  18. data/example/snoggy/config/environments/production.rb +4 -0
  19. data/example/snoggy/config/environments/test.rb +6 -0
  20. data/example/snoggy/config/initializers/snogmetrics.rb +14 -0
  21. data/example/snoggy/config/routes.rb +4 -0
  22. data/example/snoggy/script/about +4 -0
  23. data/example/snoggy/script/console +3 -0
  24. data/example/snoggy/script/dbconsole +3 -0
  25. data/example/snoggy/script/destroy +3 -0
  26. data/example/snoggy/script/generate +3 -0
  27. data/example/snoggy/script/performance/benchmarker +3 -0
  28. data/example/snoggy/script/performance/profiler +3 -0
  29. data/example/snoggy/script/plugin +3 -0
  30. data/example/snoggy/script/runner +3 -0
  31. data/example/snoggy/script/server +3 -0
  32. data/example/snoggy/vendor/plugins/snogmetrics/init.rb +4 -0
  33. data/lib/snogmetrics.rb +164 -0
  34. data/rails/init.rb +4 -0
  35. data/spec/snogmetrics_spec.rb +132 -0
  36. data/spec/spec.opts +1 -0
  37. data/spec/spec_helper.rb +15 -0
  38. metadata +100 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ /coverage
18
+ /rdoc
19
+ /yardoc
20
+ /coverage
21
+ /pkg
22
+ /.bundle
23
+
24
+ ## PROJECT::SPECIFIC
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source :gemcutter
2
+
3
+ group :development do
4
+ gem 'rake'
5
+ gem 'jeweler'
6
+ gem 'yard'
7
+ gem 'rails', '>= 2.3.5'
8
+ end
9
+
10
+ group :test do
11
+ gem 'rspec', '>= 1.3.0'
12
+ gem 'rcov'
13
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Theo
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.mdown ADDED
@@ -0,0 +1,50 @@
1
+ # SNOGmetrics
2
+
3
+ SNOGmetrics is a bridge between Rails and KISSmetrics' JavaScript API.
4
+
5
+ ## But KISSmetrics has a Ruby API!
6
+
7
+ Yes, but it's not as good as the JavaScript one, they even say so themselves:
8
+
9
+ > One thing to note about the Ruby API is that it is not as full featured as the JavaScript client. Therefore, in most cases we recommend using the JavaScript client. However, some things are easier to track server-side, therefore we have provided a basic Ruby client.
10
+
11
+ It's true, but why settle for either or?
12
+
13
+ SNOGmetrics works similarly to flash messages. Events are recorded and saved to the session, and are then sent when the next page is rendered. This way you get all of the benefits of the JavaScript API, but you can record events in your controllers. All you have to do is install this gem, configure it, and add a snipplet of code to your layout.
14
+
15
+ ## How do I use it?
16
+
17
+ 1. `gem install snogmetrics`
18
+ 2. Edit `config/environment.rb` and add `config.gem 'snogmetrics'`
19
+ 3. Edit your layout(s) and add `<%= km.js! %>` where you keep your JavaScript includes.
20
+ 4. Replace all your `KM.record(...)` and `KM.identify(...)` calls in JavaScript with calls to `km.record(...)` and `km.identify(...)`
21
+
22
+ Have a look at the included example application to see it in action.
23
+
24
+ ## Does it use the asynchronous API?
25
+
26
+ Yes it does.
27
+
28
+ ## What if I want to call KISSmetrics from both my controllers _and_ JavaScript?
29
+
30
+ Just do it. You need to make sure that the `_kmq` array exists, though. SNOGmetrics will define it where you place <%= km.js! %>, but that is usually at the bottom of the page (with the async API you could probably put it at the top if you wanted to), so if you want to add things to `_kmq` before that you need to define it yourself. Just add `var _kmq = _kmq || []` and you're set.
31
+
32
+ ## Anything else I should know?
33
+
34
+ Yes, SNOGmetrics will _not_ output the KISSmetrics API code unless `RAILS_ENV` is `production`. Instead it will output code that logs all calls to the console (if `console` is defined).
35
+
36
+ In a future version this behaviour might be overrideable.
37
+
38
+ ## Note on Patches/Pull Requests
39
+
40
+ * Fork the project.
41
+ * Make your feature addition or bug fix.
42
+ * Add tests for it. This is important so I don't break it in a
43
+ future version unintentionally.
44
+ * Commit, do not mess with rakefile, version, or history.
45
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
46
+ * Send me a pull request. Bonus points for topic branches.
47
+
48
+ ## Copyright
49
+
50
+ Copyright (c) 2010 Theo Hultberg / Burt. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'spec/rake/spectask'
2
+
3
+
4
+ begin
5
+ require 'jeweler'
6
+ require File.expand_path('../lib/snogmetrics', __FILE__)
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = 'snogmetrics'
9
+ gem.summary = %Q{SNOGmetrics is a KISSmetrics helper for Rails}
10
+ gem.description = %Q{SNOGmetrics gives you the best of both worlds: access to KISSmetrics' JavaScript API through Ruby}
11
+ gem.email = 'theo@iconara.net'
12
+ gem.homepage = 'http://github.com/iconara/snogmetrics'
13
+ gem.authors = ['Theo']
14
+ gem.version = Snogmetrics::VERSION
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
20
+ end
21
+
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ begin
38
+ require 'yard'
39
+ YARD::Rake::YardocTask.new
40
+ rescue LoadError
41
+ task :yardoc do
42
+ abort 'YARD is not available. In order to run yardoc, you must: sudo gem install yard'
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ /log
@@ -0,0 +1,7 @@
1
+ # SNOGmetrics example application
2
+
3
+ This is a small Rails application that uses SNOGmetrics. Look in `app/controllers/snogs_controller.rb` to see how you interact with the API from a controller, and look at `app/views/layouts/application.html.erb` to see the snipplet you need to add to your layout file.
4
+
5
+ Because it's easier for me when I code I've added SNOGmetrics as a plugin in the `vendor/plugins` directory (by way of symlinks), but in a real application you would add the gem in `config/environment.rb` (there's a out-commented line there if you want to see how it's done).
6
+
7
+ To set the KISSmetrics API key you need to add an initializer, see `config/initializers/snogmetrics.rb` for an example.
@@ -0,0 +1,10 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5
+
6
+ require 'rake'
7
+ require 'rake/testtask'
8
+ require 'rake/rdoctask'
9
+
10
+ require 'tasks/rails'
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,9 @@
1
+ class SnogsController < ApplicationController
2
+
3
+ def create
4
+ km.identify(params[:snog][:who])
5
+ km.record('want_to_snog', :whom => params[:snog][:whom])
6
+ redirect_to thank_you_snogs_path
7
+ end
8
+
9
+ end
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4
+ <head>
5
+ <title>SNOGmetrics</title>
6
+ </head>
7
+ <body>
8
+ <%= yield %>
9
+ </body>
10
+
11
+ <%= km.js! %>
12
+ </html>
@@ -0,0 +1,11 @@
1
+ <% form_for :snog, :url => {:action => :create} do |f| -%>
2
+ <p>
3
+ <%= f.label :who, 'Who are you?' %><br/>
4
+ <%= f.text_field :who %>
5
+ </p>
6
+ <p>
7
+ <%= f.label :whom, 'Whom would you like to snog?' %><br/>
8
+ <%= f.text_field :whom %>
9
+ </p>
10
+ <p><%= f.submit 'Fullfill my wish!' %></p>
11
+ <% end -%>
@@ -0,0 +1 @@
1
+ Thank you for participating!
@@ -0,0 +1,110 @@
1
+ # Don't change this file!
2
+ # Configure your app in config/environment.rb and config/environments/*.rb
3
+
4
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
5
+
6
+ module Rails
7
+ class << self
8
+ def boot!
9
+ unless booted?
10
+ preinitialize
11
+ pick_boot.run
12
+ end
13
+ end
14
+
15
+ def booted?
16
+ defined? Rails::Initializer
17
+ end
18
+
19
+ def pick_boot
20
+ (vendor_rails? ? VendorBoot : GemBoot).new
21
+ end
22
+
23
+ def vendor_rails?
24
+ File.exist?("#{RAILS_ROOT}/vendor/rails")
25
+ end
26
+
27
+ def preinitialize
28
+ load(preinitializer_path) if File.exist?(preinitializer_path)
29
+ end
30
+
31
+ def preinitializer_path
32
+ "#{RAILS_ROOT}/config/preinitializer.rb"
33
+ end
34
+ end
35
+
36
+ class Boot
37
+ def run
38
+ load_initializer
39
+ Rails::Initializer.run(:set_load_path)
40
+ end
41
+ end
42
+
43
+ class VendorBoot < Boot
44
+ def load_initializer
45
+ require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
46
+ Rails::Initializer.run(:install_gem_spec_stubs)
47
+ Rails::GemDependency.add_frozen_gem_path
48
+ end
49
+ end
50
+
51
+ class GemBoot < Boot
52
+ def load_initializer
53
+ self.class.load_rubygems
54
+ load_rails_gem
55
+ require 'initializer'
56
+ end
57
+
58
+ def load_rails_gem
59
+ if version = self.class.gem_version
60
+ gem 'rails', version
61
+ else
62
+ gem 'rails'
63
+ end
64
+ rescue Gem::LoadError => load_error
65
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
66
+ exit 1
67
+ end
68
+
69
+ class << self
70
+ def rubygems_version
71
+ Gem::RubyGemsVersion rescue nil
72
+ end
73
+
74
+ def gem_version
75
+ if defined? RAILS_GEM_VERSION
76
+ RAILS_GEM_VERSION
77
+ elsif ENV.include?('RAILS_GEM_VERSION')
78
+ ENV['RAILS_GEM_VERSION']
79
+ else
80
+ parse_gem_version(read_environment_rb)
81
+ end
82
+ end
83
+
84
+ def load_rubygems
85
+ min_version = '1.3.2'
86
+ require 'rubygems'
87
+ unless rubygems_version >= min_version
88
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
89
+ exit 1
90
+ end
91
+
92
+ rescue LoadError
93
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
94
+ exit 1
95
+ end
96
+
97
+ def parse_gem_version(text)
98
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
99
+ end
100
+
101
+ private
102
+ def read_environment_rb
103
+ File.read("#{RAILS_ROOT}/config/environment.rb")
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # All that for this:
110
+ Rails.boot!
@@ -0,0 +1,13 @@
1
+ RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION
2
+
3
+ require File.join(File.dirname(__FILE__), 'boot')
4
+
5
+ Rails::Initializer.run do |config|
6
+ # Usually you would add SNOGmetrics by adding the gem here, but in this
7
+ # example app I have put the code as a plugin, because it's more convenient
8
+ # when I code new features.
9
+ #config.gem 'snogmetrics'
10
+
11
+ config.frameworks -= [:active_record, :active_resource, :action_mailer]
12
+ config.action_controller.session = {:key => '_snoggy_session', :secret => 'd08d2ef897ba8d7477bc3088dde396ac'}
13
+ end
@@ -0,0 +1,6 @@
1
+ config.cache_classes = false
2
+ config.whiny_nils = true
3
+ config.action_controller.consider_all_requests_local = true
4
+ config.action_view.debug_rjs = true
5
+ config.action_controller.perform_caching = false
6
+ config.action_mailer.raise_delivery_errors = false
@@ -0,0 +1,4 @@
1
+ config.cache_classes = true
2
+ config.action_controller.consider_all_requests_local = false
3
+ config.action_controller.perform_caching = true
4
+ config.action_view.cache_template_loading = true
@@ -0,0 +1,6 @@
1
+ config.cache_classes = true
2
+ config.whiny_nils = true
3
+ config.action_controller.consider_all_requests_local = true
4
+ config.action_controller.perform_caching = false
5
+ config.action_view.cache_template_loading = true
6
+ config.action_controller.allow_forgery_protection = false
@@ -0,0 +1,14 @@
1
+ # This is where you configure SNOGmetrics. Just override the #kissmetrics_api_key
2
+ # method of the module to return the API key.
3
+ module Snogmetrics
4
+ def kissmetrics_api_key
5
+ 'abc123'
6
+ end
7
+ end
8
+
9
+ # If you need to load the API from a YAML file, you can do something like the
10
+ # following. It loads the key and puts it in a local variable, then it overrides
11
+ # the #kissmetrics_api_key method with a closure that has access to the local
12
+ # variable 'key'.
13
+ #key = YAML.load(ERB.new(File.read('path/to/file.yml')).result)[RAILS_ENV].symbolize_keys[:kissmetrics_api_key]
14
+ #Snogmetrics.send(:define_method, :kissmetrics_api_key) { key }
@@ -0,0 +1,4 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resources :snogs, :only => %w(new create), :collection => {:thank_you => :get}
3
+ map.root :controller => :snogs, :action => :new
4
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ $LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
4
+ require 'commands/about'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/dbconsole'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/benchmarker'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/profiler'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/plugin'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/runner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/server'
@@ -0,0 +1,4 @@
1
+ require 'snogmetrics'
2
+
3
+ ActionController::Base.send(:include, Snogmetrics)
4
+ ActionView::Base.send(:include, Snogmetrics)
@@ -0,0 +1,164 @@
1
+ module Snogmetrics
2
+ VERSION = '0.1.0'
3
+
4
+ def km
5
+ @km_api ||= KissmetricsApi.new(kissmetrics_api_key, session)
6
+ end
7
+
8
+ # Override this method to set the KISSmetrics API key
9
+ def kissmetrics_api_key
10
+ ''
11
+ end
12
+
13
+ private
14
+
15
+ class KissmetricsApi
16
+ include ERB::Util
17
+
18
+ def initialize(api_key, session)
19
+ @session = session
20
+ @api_key = api_key
21
+ end
22
+
23
+ def record(*args)
24
+ raise 'Not enough arguments' if args.size == 0
25
+ raise 'Too many arguments' if args.size > 2
26
+
27
+ @session[:km_events] ||= []
28
+
29
+ if args.size == 1 && args.first.is_a?(Hash)
30
+ @session[:km_events] << {:properties => args.first}
31
+ elsif args.size == 1
32
+ @session[:km_events] << {:name => args.first}
33
+ else
34
+ @session[:km_events] << {:name => args.first, :properties => args.last}
35
+ end
36
+ end
37
+
38
+ def identify(identity)
39
+ unless user_identified?(identity)
40
+ @session[:km_identity] = identity
41
+ @session[:km_user_identified] = nil
42
+ end
43
+ end
44
+
45
+ def js(options={})
46
+ options = {:reset => false}.merge(options)
47
+
48
+ buffer = []
49
+
50
+ unless user_identified? || @session[:km_identity].blank?
51
+ identity = html_escape(@session[:km_identity])
52
+
53
+ buffer << push_call('identify', identity)
54
+
55
+ user_identified! if options[:reset]
56
+ end
57
+
58
+ unless events.empty?
59
+ safe_events.each do |event|
60
+ if event[:name].blank?
61
+ buffer << push_call('record', event[:properties])
62
+ elsif event[:properties].blank?
63
+ buffer << push_call('record', event[:name])
64
+ else
65
+ buffer << push_call('record', event[:name], event[:properties])
66
+ end
67
+ end
68
+
69
+ reset_events! if options[:reset]
70
+ end
71
+
72
+ if buffer.empty?
73
+ ''
74
+ else
75
+ <<-JAVASCRIPT
76
+ <script type="text/javascript">
77
+ var _kmq = _kmq || [];
78
+ #{api_js}
79
+ #{buffer.join("\n")}
80
+ </script>
81
+ JAVASCRIPT
82
+ end
83
+ end
84
+
85
+ def js!
86
+ js(:reset => true)
87
+ end
88
+
89
+ private
90
+
91
+ def user_identified?(who=nil)
92
+ if who
93
+ @session[:km_user_identified] == who
94
+ else
95
+ !!@session[:km_user_identified]
96
+ end
97
+ end
98
+
99
+ def push_call(*args)
100
+ %(_kmq.push(#{args.to_json});)
101
+ end
102
+
103
+ def api_js
104
+ if Rails.env.production?
105
+ %((function(){function _kms(u,d){if(navigator.appName.indexOf("Microsoft")==0 && d)document.write("<scr"+"ipt defer='defer' async='true' src='"+u+"'></scr"+"ipt>");else{var s=document.createElement('script');s.type='text/javascript';s.async=true;s.src=u;(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(s);}}_kms('https://i.kissmetrics.com/i.js');_kms('http'+('https:'==document.location.protocol ? 's://s3.amazonaws.com/' : '://')+'scripts.kissmetrics.com/#{@api_key}.1.js',1);})();)
106
+ else
107
+ <<-JS
108
+ var KM = {
109
+ record: function() {
110
+ _kmq.push(["record"].concat(Array.prototype.slice.apply(arguments)));
111
+ },
112
+ identify: function() {
113
+ _kmq.push(["identify"].concat(Array.prototype.slice.apply(arguments)));
114
+ }
115
+ };
116
+
117
+ if (window.console) {
118
+ _kmq = (function(queue) {
119
+ function printCall() {
120
+ console.dir(arguments);
121
+ }
122
+
123
+ for (var i = 0; i < queue.length; i++) {
124
+ printCall.apply(null, queue[i]);
125
+ }
126
+
127
+ return {push: printCall};
128
+ })(_kmq);
129
+ }
130
+ JS
131
+ end
132
+ end
133
+
134
+ def events
135
+ @session[:km_events] || []
136
+ end
137
+
138
+ def reset_events!
139
+ @session[:km_events] = []
140
+ end
141
+
142
+ def user_identified!
143
+ @session[:km_user_identified] = @session[:km_identity]
144
+ @session[:km_identity] = nil
145
+ end
146
+
147
+ def safe_properties(hash)
148
+ return {} if hash.nil? || hash.empty?
149
+ hash.keys.inject({}) do |h, k|
150
+ h[html_escape(k)] = html_escape(hash[k])
151
+ h
152
+ end
153
+ end
154
+
155
+ def safe_events
156
+ events.map do |event|
157
+ safe_event = {}
158
+ safe_event[:name] = html_escape(event[:name].strip) unless event[:name].blank?
159
+ safe_event[:properties] = safe_properties(event[:properties]) unless event[:properties].blank?
160
+ safe_event
161
+ end
162
+ end
163
+ end
164
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'snogmetrics'
2
+
3
+ ActionController::Base.send(:include, Snogmetrics)
4
+ ActionView::Base.send(:include, Snogmetrics)
@@ -0,0 +1,132 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+
4
+ module Rails
5
+ def self.env
6
+ self
7
+ end
8
+
9
+ def self.production?
10
+ false
11
+ end
12
+ end
13
+
14
+
15
+ describe Snogmetrics do
16
+
17
+ before do
18
+ @session = {}
19
+ @context = Object.new
20
+ @context.extend(Snogmetrics)
21
+ @context.stub!(:session).and_return(@session)
22
+ @context.stub!(:kissmetrics_api_key).and_return('abc123')
23
+ end
24
+
25
+ describe '#record' do
26
+ it 'will output code that pushes an event with the specified name and properties' do
27
+ @context.km.record('hello world', :foo => 'bar')
28
+ @context.km.js.should include('_kmq.push(["record","hello world",{"foo":"bar"}]);')
29
+ end
30
+
31
+ it 'will output code that pushes an event with name only' do
32
+ @context.km.record('foo')
33
+ @context.km.js.should include('_kmq.push(["record","foo"]);')
34
+ end
35
+
36
+ it 'will output code that pushes an event with properties only' do
37
+ @context.km.record({:foo => 'bar', :plink => :plonk})
38
+ @context.km.js.should match(%r#_kmq.push\(\["record",\{(?:"foo":"bar","plink":"plonk"|"plink":"plonk","foo":"bar")\}\]\)#)
39
+ end
40
+
41
+ it 'complains if called without arguments' do
42
+ running { @context.km.record }.should raise_error
43
+ end
44
+
45
+ it 'complains if called with more than two arguments' do
46
+ running { @context.km.record(1, 2, 3) }.should raise_error
47
+ end
48
+
49
+ it 'will output code that pushes events with the same name in the order they were recorded' do
50
+ @context.km.record('An important event', :p => 3)
51
+ @context.km.record('An important event', :p => 4)
52
+ js = @context.km.js
53
+ js.should include('_kmq.push(["record","An important event",{"p":"3"}]);')
54
+ js.should include('_kmq.push(["record","An important event",{"p":"4"}]);')
55
+ js.index('_kmq.push(["record","An important event",{"p":"3"}]);').should < js.index('_kmq.push(["record","An important event",{"p":"4"}]);')
56
+ end
57
+ end
58
+
59
+ describe '#identify' do
60
+ it 'will output code that pushes an identify call with the provided identity' do
61
+ @context.km.identify('Phil')
62
+ @context.km.js.should include('_kmq.push(["identify","Phil"]);')
63
+ end
64
+
65
+ it 'will only output the last identity set' do
66
+ @context.km.identify('Phil')
67
+ @context.km.identify('Anne')
68
+ @context.km.identify('Steve')
69
+ @context.km.js.should_not include('Phil')
70
+ @context.km.js.should_not include('Anne')
71
+ @context.km.js.should include('Steve')
72
+ end
73
+ end
74
+
75
+ describe '#js' do
76
+ it 'outputs nothing if there are no events and no identity' do
77
+ @context.km.js.should be_empty
78
+ end
79
+
80
+ context 'in production' do
81
+ before do
82
+ Rails.stub!(:env).and_return(mock('env', :production? => true))
83
+ end
84
+
85
+ it 'outputs a JavaScript tag that loads the KISSmetrics API' do
86
+ @context.km.identify('Phil')
87
+ @context.km.js.should include('scripts.kissmetrics.com/abc123.1.js')
88
+ end
89
+ end
90
+
91
+ it 'outputs code that conditionally sets the _kmq variable' do
92
+ @context.km.identify('Phil')
93
+ @context.km.js.should include('var _kmq = _kmq || [];')
94
+ end
95
+
96
+ it 'outputs code that pushes an event for every #record call' do
97
+ @context.km.record('1')
98
+ @context.km.record('2')
99
+ @context.km.record('3')
100
+ @context.km.js.scan(/_kmq.push\(\["record","\d"\]\)/).size.should == 3
101
+ end
102
+
103
+ it 'resets the session when passed :reset => true' do
104
+ @context.km.record('hello world')
105
+ @context.km.js(:reset => true)
106
+ @context.km.js.should be_empty
107
+ end
108
+ end
109
+
110
+ describe '#js!' do
111
+ it 'works like #js(:reset => true)' do
112
+ @context.km.record('hello world')
113
+ @context.km.js!
114
+ @context.km.js.should be_empty
115
+ end
116
+
117
+ it 'does not push an identify call if the identity has already been sent once' do
118
+ @context.km.identify('Steve')
119
+ @context.km.js!
120
+ @context.km.identify('Steve')
121
+ @context.km.js!.should_not include('_kmq.push(["identify"')
122
+ end
123
+
124
+ it 'ouputs code that pushes an identify call if #identify is called with a new identity' do
125
+ @context.km.identify('Steve')
126
+ @context.km.js!
127
+ @context.km.identify('Anne')
128
+ @context.km.js!.should include('_kmq.push(["identify","Anne"])')
129
+ end
130
+ end
131
+
132
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'snogmetrics'
5
+ require 'active_support'
6
+ require 'action_view/erb/util'
7
+ require 'spec'
8
+ require 'spec/autorun'
9
+
10
+
11
+ alias :running :lambda
12
+
13
+ Spec::Runner.configure do |config|
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snogmetrics
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Theo
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-30 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: "SNOGmetrics gives you the best of both worlds: access to KISSmetrics' JavaScript API through Ruby"
22
+ email: theo@iconara.net
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.mdown
30
+ files:
31
+ - .document
32
+ - .gitignore
33
+ - Gemfile
34
+ - LICENSE
35
+ - README.mdown
36
+ - Rakefile
37
+ - example/snoggy/.gitignore
38
+ - example/snoggy/README.mdown
39
+ - example/snoggy/Rakefile
40
+ - example/snoggy/app/controllers/application_controller.rb
41
+ - example/snoggy/app/controllers/snogs_controller.rb
42
+ - example/snoggy/app/views/layouts/application.html.erb
43
+ - example/snoggy/app/views/snogs/new.html.erb
44
+ - example/snoggy/app/views/snogs/thank_you.html.erb
45
+ - example/snoggy/config/boot.rb
46
+ - example/snoggy/config/environment.rb
47
+ - example/snoggy/config/environments/development.rb
48
+ - example/snoggy/config/environments/production.rb
49
+ - example/snoggy/config/environments/test.rb
50
+ - example/snoggy/config/initializers/snogmetrics.rb
51
+ - example/snoggy/config/routes.rb
52
+ - example/snoggy/script/about
53
+ - example/snoggy/script/console
54
+ - example/snoggy/script/dbconsole
55
+ - example/snoggy/script/destroy
56
+ - example/snoggy/script/generate
57
+ - example/snoggy/script/performance/benchmarker
58
+ - example/snoggy/script/performance/profiler
59
+ - example/snoggy/script/plugin
60
+ - example/snoggy/script/runner
61
+ - example/snoggy/script/server
62
+ - example/snoggy/vendor/plugins/snogmetrics/init.rb
63
+ - lib/snogmetrics.rb
64
+ - rails/init.rb
65
+ - spec/snogmetrics_spec.rb
66
+ - spec/spec.opts
67
+ - spec/spec_helper.rb
68
+ has_rdoc: true
69
+ homepage: http://github.com/iconara/snogmetrics
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options:
74
+ - --charset=UTF-8
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.3.6
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: SNOGmetrics is a KISSmetrics helper for Rails
98
+ test_files:
99
+ - spec/snogmetrics_spec.rb
100
+ - spec/spec_helper.rb