Skip to content
This repository has been archived by the owner on Aug 10, 2020. It is now read-only.

Add Segment.io module #68

Merged
merged 7 commits into from Mar 12, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.rdoc
Expand Up @@ -23,6 +23,7 @@ Service implementations include:
* Quantcast[http://www.quantcast.com]
* MixPanel[http://www.mixpanel.com]
* Gauges[http://get.gaug.es]
* Segment.io[http://segment.io]

== Usage

Expand All @@ -40,7 +41,7 @@ Add a configuration file (config/analytical.yml) to declare your API keys, like
development:
test:

You can add different configurations for different environments.
You can add different configurations for different environments.

By default, all the declared analytics modules are loaded. You can override this behavior in the controller.

Expand Down Expand Up @@ -91,6 +92,29 @@ This can be useful for enabling the console logger optionally in your app, based
controller.use_console_logger? ? [:console] : modules
}

You can also configure modules in the controller by passing a hash to the :modules option

analytical :modules => { :google => { key: 'UA-5555555-5' } }

Finally it is also possible to dynamically specify what modules to use and their configurations, which can come in handy if your site uses multi-tenancy, where every tenant might not wish to use the same modules or configurations for each module.

analytical :modules => lambda{ |controller| controller.analytical_modules }

In this case we would then implement a method in the controller that could look like this:

def analytical_modules
case current_tenant.name.parameterize
when "site-1"
{
:google => { key: 'UA-5555555-5' }
}
when "site-2"
{
:google => { key: 'UA-1111111-1' }
}
end
end
hide_action :analytical_modules

== Adding new modules

Expand Down Expand Up @@ -151,6 +175,7 @@ These fine folks have contributed patches and new features to this project:
* {Kurt Werle}[http://github.com/kwerle]
* {Olivier Lauzon}[http://github.com/olauzon]
* {Chris Ricca}[https://github.com/ChrisRicca]
* {Thomas Dippel}[https://github.com/dipth]

Thanks guys!

Expand Down
9 changes: 9 additions & 0 deletions lib/analytical.rb
Expand Up @@ -36,6 +36,15 @@ def analytical
:ssl => request.ssl?,
:controller => self,
})
if options[:modules] && (options[:modules].is_a?(Hash) || options[:modules].is_a?(Proc))
items = options[:modules].is_a?(Hash) ? options[:modules] : options[:modules].call(self)
modules = []
items.each do |k,v|
options[k.to_sym] = v.symbolize_keys
modules << k.to_sym
end
options[:modules] = modules
end
if options[:disable_if] && options[:disable_if].call(self)
options[:modules] = []
end
Expand Down
41 changes: 41 additions & 0 deletions lib/analytical/modules/segment_io.rb
@@ -0,0 +1,41 @@
module Analytical
module Modules
class SegmentIo
include Analytical::Modules::Base

def initialize(options={})
super
@tracking_command_location = :head_prepend
end

def init_javascript(location)
init_location(location) do
js = <<-HTML
<!-- Analytical Init: Segment.io -->
<script type="text/javascript">
window.analytics=window.analytics||[];window.analytics.load=function(apiKey){var script=document.createElement('script');script.type='text/javascript';script.async=true;script.src=('https:'===document.location.protocol?'https://':'http://')+'d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/'+apiKey+'/analytics.min.js';var firstScript=document.getElementsByTagName('script')[0];firstScript.parentNode.insertBefore(script,firstScript);var methodFactory=function(type){return function(){window.analytics.push([type].concat(Array.prototype.slice.call(arguments,0)))}};var methods=['identify','track','trackLink','trackForm','trackClick','trackSubmit','pageview','ab','alias','ready'];for(var i=0;i<methods.length;i++){window.analytics[methods[i]]=methodFactory(methods[i])}};window.analytics.load('#{options[:key]}');
</script>
HTML
js
end
end

def track(*args)
if args.any?
%(window.analytics.pageview("#{args.first}");)
else
%(window.analytics.pageview();)
end
end

def identify(id, attributes = {})
%(window.analytics.identify("#{id}", #{attributes.to_json});)
end

def event(name, attributes = {})
%(window.analytics.track("#{name}", #{attributes.to_json});)
end

end
end
end
61 changes: 61 additions & 0 deletions spec/analytical/modules/segment_io_spec.rb
@@ -0,0 +1,61 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')

describe Analytical::Modules::SegmentIo do
before(:each) do
@parent = mock('api', :options=>{:segment_io=>{:key=>'abc'}})
end
describe 'on initialize' do
it 'should set the command_location' do
a = described_class.new :parent=>@parent, :key=>'abc'
a.tracking_command_location.should eq :head_prepend
end
it 'should set the options' do
a = described_class.new :parent=>@parent, :key=>'abc'
a.options.should eq({:key=>'abc', :parent=>@parent})
end
end
describe '#track' do
it 'should return the pageview javascript' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.track.should eq "window.analytics.pageview();"
@api.track('pagename', {:some=>'data'}).should eq "window.analytics.pageview(\"pagename\");"
end
end
describe '#event' do
it 'should return the track javascript' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.event('pagename').should eq "window.analytics.track(\"pagename\", {});"
end

it 'should include data value' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.event('pagename', {:value=>555, :more=>'info'}).should eq "window.analytics.track(\"pagename\", {\"value\":555,\"more\":\"info\"});"
end
it 'should not include data if there is no value' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.event('pagename', {:more=>'info'}).should eq "window.analytics.track(\"pagename\", {\"more\":\"info\"});"
end
it 'should not include data if it is not a hash' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.event('pagename', 555).should eq "window.analytics.track(\"pagename\", 555);"
end
end
describe '#identify' do
it 'should return the identify javascript' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.identify('id', {:email=>'test@test.com'}).should == "window.analytics.identify(\"id\", {\"email\":\"test@test.com\"});"
end
end

describe '#init_javascript' do
it 'should return the init javascript' do
@api = described_class.new :parent=>@parent, :key=>'abcdef'
@api.init_javascript(:head_append).should eq ''
@api.init_javascript(:head_prepend).should =~ /window.analytics=/
@api.init_javascript(:head_prepend).should =~ /abcdef/
@api.init_javascript(:head_prepend).should =~ /analytics.js\/v1/
@api.init_javascript(:body_prepend).should eq ''
@api.init_javascript(:body_append).should eq ''
end
end
end
29 changes: 25 additions & 4 deletions spec/analytical_spec.rb
Expand Up @@ -15,8 +15,8 @@ class DummyForInit

def self.helper_method(*a); end
def request
RSpec::Mocks::Mock.new 'request',
:'ssl?'=>true,
RSpec::Mocks::Mock.new 'request',
:'ssl?'=>true,
:user_agent=>'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0'
end
end
Expand All @@ -30,6 +30,27 @@ def request
d.options[:string_option].should == "string"
end

it 'should load module configurations from hash' do
options = { :modules => { :console => { :some_key => 'rubberduck' } }}
DummyForInit.analytical options
a = DummyForInit.new.analytical
a.options[:modules].should include(:console)
a.options[:console].should eq({ :some_key => 'rubberduck' })
end

it 'should load module configurations from a lambda' do
class DummyForInit
def analytical_modules
{ :console => { :some_key => 'rubberduck' } }
end
end
options = { :modules => lambda { |controller| controller.analytical_modules }}
DummyForInit.analytical options
a = DummyForInit.new.analytical
a.options[:modules].should include(:console)
a.options[:console].should eq({ :some_key => 'rubberduck' })
end

it 'should preserve :javascript_helpers option' do
options = { :javascript_helpers => false, :modules => [] }
DummyForInit.analytical options
Expand All @@ -42,12 +63,12 @@ def request
d = DummyForInit.new.analytical
d.options[:modules].should == [:google]
end

describe 'conditionally disabled' do
it 'should set the modules to []' do
DummyForInit.analytical :disable_if => lambda { |x| true }
d = DummyForInit.new
d.analytical.options[:modules].should == []
d.analytical.options[:modules].should == []
end
end

Expand Down