analytical 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,8 +3,53 @@
3
3
  Gem for managing multiple analytics services in your rails app.
4
4
  Initial service implementations include: Google Analytics, Clicky[http://getclicky.com], and KISSMetrics[http://kissmetrics.com].
5
5
 
6
+ == Usage
7
+
8
+ Add the following to your controllers:
9
+
10
+ analytical :modules=>[:console, :google, :clicky]
11
+
12
+ Then, in your template files, you'll want to add the analytical helper methods for initializing the tracking javascript:
13
+
14
+ <!DOCTYPE html>
15
+ <html>
16
+ <head>
17
+ <title>Example</title>
18
+ <%= stylesheet_link_tag :all %>
19
+ <%= javascript_include_tag :defaults %>
20
+ <%= csrf_meta_tag %>
21
+ <% analytical.identify '5', :email=>'josh@transfs.com' %>
22
+ <%= raw analytical.head_javascript %>
23
+ </head>
24
+ <body>
25
+ <%= raw analytical.body_prepend_javascript %>
26
+ <%= yield %>
27
+ <%= raw analytical.body_append_javascript %>
28
+ </body>
29
+ </html>
30
+
31
+ Note the example above also includes an identify() command that will apply to every page. More likely, you'll want to make this identify() command conditional so that it only applies when you have a logged-in user:
32
+
33
+ <% analytical.identify(current_user.id, :email=>current_user.email) if current_user %>
34
+
35
+ You can sprinkle the track() and event() tracking methods throughout your views & controllers as needed.
36
+
37
+ analytical.track '/a/really/nice/url'
38
+ analytical.event 'Some Awesome Event', :with=>:data
39
+
40
+ By default, Analytical will be disabled in development mode... and it will enable the Console module only. To change this behavior, you can pass a Proc/lambda to the :disable_if option, as well as specify the :development_modules that you want to use:
41
+
42
+ analytical :modules=>[:google], :development_modules=>[], :disable_if=>lambda{ |controller| controller.i_can_haz_tracking? }
43
+
44
+ == Adding new modules
45
+
46
+ New modules should be fairly easy to add. Follow the structure that I've used in the Clicky, Google, and KISSMetrics modules... and you should be fine. All modules should include the Analytical::Base::Api module, so that they have some default behavior for methods that they don't support or need.
47
+
48
+
6
49
  == Note on Patches/Pull Requests
7
50
 
51
+ I would be extremely happy to accept contributions to this project! If you think something should work differently, send me a message and I'd love to discuss your ideas. Even better:
52
+
8
53
  * Fork the project.
9
54
  * Make your feature addition or bug fix.
10
55
  * Add specs for it. This is important so I don't break it in a future version unintentionally.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.5.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{analytical}
8
- s.version = "0.3.0"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Joshua Krall"]
12
- s.date = %q{2010-04-28}
12
+ s.date = %q{2010-04-29}
13
13
  s.description = %q{Gem for managing multiple analytics services in your rails app.}
14
14
  s.email = %q{josh@transfs.com}
15
15
  s.extra_rdoc_files = [
@@ -6,7 +6,7 @@
6
6
  <%= javascript_include_tag :defaults %>
7
7
  <%= csrf_meta_tag %>
8
8
 
9
- <% raw analytical.identify '5', :email=>'josh@transfs.com' %>
9
+ <% analytical.identify '5', :email=>'josh@transfs.com' %>
10
10
  <%= raw analytical.head_javascript %>
11
11
  </head>
12
12
  <body>
@@ -24,24 +24,22 @@ module Analytical
24
24
  end
25
25
  end if File.exists?("#{RAILS_ROOT}/config/analytical.yml")
26
26
 
27
- self.analytical_options = self.analytical_options.merge config_options
28
-
29
- if self.analytical_options[:disable_if].call
30
- self.analytical_options[:modules] = self.analytical_options[:development_modules]
31
- end
32
- self.analytical_options[:modules].each do |m|
33
- Analytical::Api.send :include, "Analytical::#{m.to_s.camelize}".constantize
34
- end
27
+ self.analytical_options = self.analytical_options.reverse_merge config_options
35
28
  end
36
29
 
37
30
  module InstanceMethods
38
31
  # any method placed here will apply to instances
39
32
 
40
33
  def analytical
41
- options = self.class.analytical_options.merge({
42
- :ssl => request.ssl?
43
- })
44
- @analytical ||= Analytical::Api.new options
34
+ @analytical ||= begin
35
+ options = self.class.analytical_options.merge({
36
+ :ssl => request.ssl?
37
+ })
38
+ if options[:disable_if].call(self)
39
+ options[:modules] = options[:development_modules]
40
+ end
41
+ Analytical::Api.new options
42
+ end
45
43
  end
46
44
  end
47
45
 
@@ -37,7 +37,7 @@ module Analytical
37
37
  end
38
38
 
39
39
  def identify(id, *args)
40
- data = { :id=>id }.merge(args.first)
40
+ data = { :id=>id }.merge(args.first || {})
41
41
  code = <<-HTML
42
42
  <script type='text/javascript'>
43
43
  var clicky_custom_session = #{data.to_json};
@@ -2,7 +2,6 @@ module Analytical
2
2
  module Console
3
3
  class Api
4
4
  include Analytical::Base::Api
5
- include ActionView::Helpers::JavaScriptHelper
6
5
 
7
6
  def initialize(parent, options={})
8
7
  super
@@ -21,15 +20,33 @@ module Analytical
21
20
  end
22
21
 
23
22
  def track(*args)
24
- "console.log(\"Analytical Track: #{escape_javascript args.to_json}\");"
23
+ "console.log(\"Analytical Track: \"+\"#{escape args.first}\");"
25
24
  end
26
25
 
27
26
  def identify(id, *args)
28
- "console.log(\"Analytical Identify: #{id} #{escape_javascript args.to_json}\");"
27
+ data = args.first || {}
28
+ "console.log(\"Analytical Identify: \"+\"#{id}\"+\" \"+$H(#{data.to_json}).toJSON());"
29
29
  end
30
30
 
31
31
  def event(name, *args)
32
- "console.log(\"Analytical Event: #{name} #{escape_javascript args.to_json}\");"
32
+ data = args.first || {}
33
+ "console.log(\"Analytical Event: \"+\"#{name}\"+\" \"+$H(#{data.to_json}).toJSON());"
34
+ end
35
+
36
+ private
37
+
38
+ CONSOLE_JS_ESCAPE_MAP = {
39
+ '\\' => '\\\\',
40
+ '</' => '<\/',
41
+ "\r\n" => '\n',
42
+ "\n" => '\n',
43
+ "\r" => '\n',
44
+ '"' => '\\"',
45
+ "'" => "\\'"
46
+ }
47
+
48
+ def escape(js)
49
+ js.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { CONSOLE_JS_ESCAPE_MAP[$1] }
33
50
  end
34
51
 
35
52
  end
@@ -21,12 +21,12 @@ module Analytical
21
21
  end
22
22
 
23
23
  def identify(id, *args)
24
- data = args.first
24
+ data = args.first || {}
25
25
  "_kmq.push([\"identify\", \"#{data[:email]}\"]);"
26
26
  end
27
27
 
28
28
  def event(name, *args)
29
- data = args.first
29
+ data = args.first || {}
30
30
  "_kmq.push([\"record\", \"#{name}\", #{data.to_json}]);"
31
31
  end
32
32
 
@@ -29,21 +29,21 @@ describe "Analytical::Clicky::Api" do
29
29
  describe '#init_javascript' do
30
30
  it 'should return the init javascript' do
31
31
  @api = Analytical::Clicky::Api.new @parent, {:key=>'abcdef'}
32
- @api.init_javascript[:head].should be_nil
33
- @api.init_javascript[:body_prepend].should be_nil
34
- @api.init_javascript[:body_append].should =~ /static.getclicky.com\/js/
35
- @api.init_javascript[:body_append].should =~ /abcdef/
32
+ @api.init_javascript(:head).should == ''
33
+ @api.init_javascript(:body_prepend).should == ''
34
+ @api.init_javascript(:body_append).should =~ /static.getclicky.com\/js/
35
+ @api.init_javascript(:body_append).should =~ /abcdef/
36
36
  end
37
37
  describe 'for an ssl connection' do
38
38
  it 'should return the ssl init code' do
39
39
  @api = Analytical::Clicky::Api.new @parent, {:key=>'abcdef', :ssl=>true}
40
- @api.init_javascript[:body_append].should =~ /https/
40
+ @api.init_javascript(:body_append).should =~ /https/
41
41
  end
42
42
  end
43
43
  describe 'with an identify command queued' do
44
44
  @api = Analytical::Clicky::Api.new @parent, {:key=>'abcdef'}
45
45
  @api.queue :identify, 'user id', {:email=>'someone@test.com'}
46
- @api.init_javascript[:body_append].should =~ /"email":\w*"someone@test\.com"/
46
+ @api.init_javascript(:body_append).should =~ /"email":\w*"someone@test\.com"/
47
47
  end
48
48
  end
49
49
  end
@@ -29,10 +29,10 @@ describe "Analytical::Google::Api" do
29
29
  describe '#init_javascript' do
30
30
  it 'should return the init javascript' do
31
31
  @api = Analytical::Google::Api.new @parent, {:key=>'abcdef'}
32
- @api.init_javascript[:head].should be_nil
33
- @api.init_javascript[:body_prepend].should =~ /google-analytics.com\/ga.js/
34
- @api.init_javascript[:body_prepend].should =~ /abcdef/
35
- @api.init_javascript[:body_append].should be_nil
32
+ @api.init_javascript(:head).should == ''
33
+ @api.init_javascript(:body_prepend).should =~ /google-analytics.com\/ga.js/
34
+ @api.init_javascript(:body_prepend).should =~ /abcdef/
35
+ @api.init_javascript(:body_append).should == ''
36
36
  end
37
37
  end
38
38
  end
@@ -35,10 +35,10 @@ describe "Analytical::KissMetrics::Api" do
35
35
  describe '#init_javascript' do
36
36
  it 'should return the init javascript' do
37
37
  @api = Analytical::KissMetrics::Api.new @parent, {:key=>'abcdef'}
38
- @api.init_javascript[:head].should be_nil
39
- @api.init_javascript[:body_prepend].should =~ /scripts.kissmetrics.com/
40
- @api.init_javascript[:body_prepend].should =~ /abcdef/
41
- @api.init_javascript[:body_append].should be_nil
38
+ @api.init_javascript(:head).should == ''
39
+ @api.init_javascript(:body_prepend).should =~ /scripts.kissmetrics.com/
40
+ @api.init_javascript(:body_prepend).should =~ /abcdef/
41
+ @api.init_javascript(:body_append).should == ''
42
42
  end
43
43
  end
44
44
  end
@@ -40,12 +40,6 @@ describe "Analytical" do
40
40
  DummyForInit.analytical
41
41
  DummyForInit.new.analytical.options[:modules] = []
42
42
  end
43
- it 'should include specific modules' do
44
- Analytical::Api.should_receive(:include).with(Analytical::Console)
45
- Analytical::Api.should_receive(:include).with(Analytical::Google)
46
- DummyForInit.analytical :modules=>[:google, :console]
47
- DummyForInit.new.analytical.options[:modules] = [:google, :console]
48
- end
49
43
  end
50
44
 
51
45
  describe 'in development mode' do
@@ -53,7 +47,6 @@ describe "Analytical" do
53
47
  Rails.env.stub!(:production?).and_return(false)
54
48
  end
55
49
  it 'should start with no modules' do
56
- Analytical::Api.should_receive(:include).with(Analytical::Console)
57
50
  DummyForInit.analytical
58
51
  DummyForInit.new.analytical.options[:modules] = [:console]
59
52
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
7
+ - 5
8
8
  - 0
9
- version: 0.3.0
9
+ version: 0.5.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Joshua Krall
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-28 00:00:00 -05:00
17
+ date: 2010-04-29 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency