Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first try at porting rack::google-analytics to rack::piwik

  • Loading branch information...
commit e058c44e77627b1030bf0835cf11943dd74bc149 0 parents
Maxwell Salzberg authored
24 .gitignore
@@ -0,0 +1,24 @@
+## MAC OS
+.DS_Store
+
+## TEXTMATE
+*.tmproj
+tmtags
+
+## EMACS
+*~
+\#*
+.\#*
+
+## VIM
+*.swp
+
+## PROJECT::GENERAL
+coverage
+rdoc
+pkg
+
+## PROJECT::SPECIFIC
+._*
+*.gem
+pkg/*
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Lee Hambley
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 README.md
@@ -0,0 +1,48 @@
+# Rack Piwik
+Adapted from Rack::Piwik
+
+Simple Rack middleware to help injecting the Piwik tracking code into the footer of your websites.
+
+## Usage
+
+#### Gemfile:
+ gem 'rack-piwik', :require => 'rack/piwik'
+
+#### Sinatra
+ ## app.rb
+ use Rack::Piwik, :piwik_url => '<url of your piwik site here>', :piwik_id => '<your piwik id here>'
+
+#### Padrino
+
+ ## app/app.rb
+ use Rack::Piwik, :piwik_url => '<url of your piwik site here>', :piwik_id => '<your piwik id here>'
+
+#### Rails
+
+ ## environment.rb:
+ config.gem 'rack-piwik', :lib => 'rack/piwik
+ config.middleware.use Rack::Piwik, :piwik_url => '<url of your piwik site here>', :piwik_id => '<your piwik id here>'
+
+## Thread Safety
+
+This middleware *should* be thread safe. Although my experience in such areas is limited, having taken the advice of those with more experience; I defer the call to a shallow copy of the environment, if this is of consequence to you please review the implementation.
+
+## Change Log
+
+* 0.1.0 Initial Release
+
+
+## Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so I don't break it in a
+ future version unintentionally.
+* Commit, do not mess with rakefile, version, or history.
+ (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)
+* Send me a pull request. Bonus points for topic branches.
+
+## Copyright
+
+Copyright (c) 2009-2011 Lee Hambley. See LICENSE for details.
+With thanks to Ralph von der Heyden http://github.com/ralph/ and Simon `cimm` Schoeters http://github.com/cimm/ - And the biggest hand to Arthur `achiu` Chiu for the huge work that went into the massive 0.9 re-factor.
33 Rakefile
@@ -0,0 +1,33 @@
+require 'rubygems'
+require 'rake'
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+ test.libs << 'lib' << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+end
+
+begin
+ require 'rcov/rcovtask'
+ Rcov::RcovTask.new do |test|
+ test.libs << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+ end
+rescue LoadError
+ task :rcov do
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
+ end
+end
+
+task :default => :test
+
+begin
+ require 'yard'
+ YARD::Rake::YardocTask.new
+rescue LoadError
+ task :yardoc do
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
+ end
+end
1  VERSION
@@ -0,0 +1 @@
+0.1.0
40 lib/rack/google-analytics.rb
@@ -0,0 +1,40 @@
+require 'rack'
+require 'erb'
+
+module Rack
+
+ class Piwik
+
+
+ def initialize(app, options = {})
+ raise ArgumentError, "piwik_url must be user" unless options[:piwik_url] and !options[:piwik_url].empty?
+ @app, @options = app, DEFAULT.merge(options)
+ end
+
+ def call(env); dup._call(env); end
+
+ def _call(env)
+ @status, @headers, @response = @app.call(env)
+ return [@status, @headers, @response] unless html?
+ response = Rack::Response.new([], @status, @headers)
+ @response.each { |fragment| response.write inject(fragment) }
+ response.finish
+ end
+
+ private
+
+ def html?; @headers['Content-Type'] =~ /html/; end
+
+ def inject(response)
+ file = @options[:async] ? 'async' : 'sync'
+ @template ||= ::ERB.new ::File.read ::File.expand_path("../templates/#{file}.erb",__FILE__)
+ if @options[:async]
+ response.gsub(%r{</head>}, @template.result(binding) + "</head>")
+ else
+ response.gsub(%r{</body>}, @template.result(binding) + "</body>")
+ end
+ end
+
+ end
+
+end
41 lib/rack/piwik.rb
@@ -0,0 +1,41 @@
+require 'rack'
+require 'erb'
+
+module Rack
+
+ class GoogleAnalytics
+
+ DEFAULT = { :async => true }
+
+ def initialize(app, options = {})
+ raise ArgumentError, "Tracker must be set!" unless options[:tracker] and !options[:tracker].empty?
+ @app, @options = app, DEFAULT.merge(options)
+ end
+
+ def call(env); dup._call(env); end
+
+ def _call(env)
+ @status, @headers, @response = @app.call(env)
+ return [@status, @headers, @response] unless html?
+ response = Rack::Response.new([], @status, @headers)
+ @response.each { |fragment| response.write inject(fragment) }
+ response.finish
+ end
+
+ private
+
+ def html?; @headers['Content-Type'] =~ /html/; end
+
+ def inject(response)
+ file = @options[:async] ? 'async' : 'sync'
+ @template ||= ::ERB.new ::File.read ::File.expand_path("../templates/#{file}.erb",__FILE__)
+ if @options[:async]
+ response.gsub(%r{</head>}, @template.result(binding) + "</head>")
+ else
+ response.gsub(%r{</body>}, @template.result(binding) + "</body>")
+ end
+ end
+
+ end
+
+end
12 lib/rack/templates/async.erb
@@ -0,0 +1,12 @@
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://<%= @options[:piwik_url]%>/" : "http://<%= @options[:piwik_url]%>/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+try {
+ var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", <%= @options[:piwik_id]%>);
+ piwikTracker.trackPageView();
+ piwikTracker.enableLinkTracking();
+} catch( err ) {}
+</script>
+<!-- End Piwik Code -->
16 rack-piwik.gemspec
@@ -0,0 +1,16 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+
+ s.name = "rack-piwik"
+ s.version = File.read('VERSION').to_s
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Maxwell Salzberg"]
+ s.email = ["maxwell@joindiaspora.com"]
+ s.homepage = "https://github.com/leehambley/rack-google-analytics"
+ s.summary = "Rack middleware to inject the Piwik tracking code into outgoing responses. Adapted from rack-google-analytics"
+ s.description = "Simple Rack middleware for implementing piwik Analytics racking in your Ruby-Rack based project."
+
+ s.files = Dir.glob("lib/**/*") + %w(README.md LICENSE)
+ s.require_path = 'lib'
+end
29 test/helper.rb
@@ -0,0 +1,29 @@
+require 'rubygems'
+require 'test/unit'
+require 'shoulda'
+require 'rack'
+require 'rack/test'
+require File.expand_path('../../lib/rack/google-analytics',__FILE__)
+
+class Test::Unit::TestCase
+ include Rack::Test::Methods
+
+ def app; Rack::Lint.new(@app); end
+
+ def mock_app(options)
+ main_app = lambda { |env|
+ request = Rack::Request.new(env)
+ case request.path
+ when '/' then [200,{ 'Content-Type' => 'application/html' },['<head>Hello world</head>']]
+ when '/test.xml' then [200,{'Content-Type' => 'application/xml'}, ['Xml here']]
+ when '/bob' then [200,{'Content-Type' => 'application/html'} ,['<body>bob here</body>']]
+ else [404,'Nothing here']
+ end
+ }
+
+ builder = Rack::Builder.new
+ builder.use Rack::GoogleAnalytics, options
+ builder.run main_app
+ @app = builder.to_app
+ end
+end
58 test/test_rack_piwik.rb
@@ -0,0 +1,58 @@
+require File.expand_path('../helper',__FILE__)
+
+class TestRackGoogleAnalytics < Test::Unit::TestCase
+
+ context "Asyncronous" do
+ context "default" do
+ setup { mock_app :async => true, :tracker => 'somebody' }
+ should "show asyncronous tracker" do
+ get "/"
+ assert_match %r{\_gaq\.push}, last_response.body
+ assert_match %r{\'\_setAccount\', \"somebody\"}, last_response.body
+ assert_match %r{</script></head>}, last_response.body
+ assert_equal "532", last_response.headers['Content-Length']
+ end
+
+ should "not add tracker to none html content-type" do
+ get "/test.xml"
+ assert_no_match %r{\_gaq\.push}, last_response.body
+ assert_match %r{Xml here}, last_response.body
+ end
+
+ should "not add without </head>" do
+ get "/bob"
+ assert_no_match %r{\_gaq\.push}, last_response.body
+ assert_match %r{bob here}, last_response.body
+ end
+ end
+
+ context "multiple sub domains" do
+ setup { mock_app :async => true, :multiple => true, :tracker => 'gonna', :domain => 'mydomain.com' }
+ should "add multiple domain script" do
+ get "/"
+ assert_match %r{'_setDomainName', \"mydomain.com\"}, last_response.body
+ assert_equal "579", last_response.headers['Content-Length']
+ end
+ end
+
+ context "multiple top-level domains" do
+ setup { mock_app :async => true, :top_level => true, :tracker => 'get', :domain => 'mydomain.com' }
+ should "add top_level domain script" do
+ get "/"
+ assert_match %r{'_setDomainName', 'none'}, last_response.body
+ assert_match %r{'_setAllowLinker', true}, last_response.body
+ end
+ end
+
+ end
+
+ context "Syncronous" do
+ setup { mock_app :async => false, :tracker => 'whatthe' }
+ should "show non-asyncronous tracker" do
+ get "/bob"
+ assert_match %r{_gat._getTracker}, last_response.body
+ assert_match %r{</script></body>}, last_response.body
+ assert_match %r{\"whatthe\"}, last_response.body
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.