rubango 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Jonah Honeyman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ rubango
2
+ ================
3
+
4
+ A ruby API wrapper for integrating your rails application with [Totango](http://www.totango.com).
5
+
6
+ Installation
7
+ ------------
8
+
9
+ gem install rubango # use 'totango' when require-ing
10
+
11
+ Usage
12
+ -----
13
+
14
+ First, build your client with your API id:
15
+
16
+ Totango.srv_id "YOUR_ID_GOES_HERE"
17
+
18
+ By default, Totango will not make remote calls. It will print a debug message about the URL that would be getting hit. This message can be annoying when testing. To turn the message off, use `Totango::Config`:
19
+
20
+ Totango::Config[:suppress_output] = true
21
+
22
+ To make the remote call to totango.com you must turn the tracker on:
23
+
24
+ Totango.on! # you will probably only want to do this in production mode.
25
+
26
+ You now interact with `Totango.client` to do your bidding:
27
+
28
+ Totango.client.track({
29
+ :organization => "Current organization",
30
+ :user => "Current user",
31
+ :activity => "Current activity",
32
+ :module => "Current module"
33
+ })
34
+
35
+ There is also the option for integration with different ruby frameworks.
36
+
37
+ ### Rails
38
+
39
+ class ApplicationController < ActionController::Base
40
+ include Totango::Adapters::Rails
41
+
42
+ #...
43
+ end
44
+
45
+ That will build your tracking code based around a couple of sane defaults. By default it will set the current module to `params[:controller]` and activity to `params[:action]`. If you wish to override the defaults you can do so in your controllers:
46
+
47
+ class MyController < ApplictationController
48
+ sp_default :activity, "Whatever you want here"
49
+ # You may also send a Proc object as the value so that it is
50
+ # evaluated in the context of the current controller. For example:
51
+ sp_default :user, proc { method_to_determine_current_user }
52
+ end
53
+
54
+ To track different actions, you must now tell Totango which actions you would like to track:
55
+
56
+ class MyController < ApplictationController
57
+ track :index
58
+ track :show, "Override default activity text here"
59
+ track :edit, :user => "override other defaults in a hash"
60
+ track :destroy, :if => proc { params[:my_boolean] } # Use conditionals to only run tracking based on the eval'd code in the Proc object
61
+ end
62
+
63
+ ### Rolling your own adapter
64
+
65
+ There are currently adapters for rails and merb, but it is simple to write your own adapter
66
+
67
+ module MySPAdapter
68
+ extend Totango::Adapters::Base
69
+
70
+ register_adapter :my_adapter
71
+ hook_method :before_hook # Hook method name that will be called before or after each action
72
+ action_finder :action_name # Method that determines the current action being hit
73
+
74
+ # You can set defaults from here that will be set on the controller class
75
+ # that includes your adapter and all of its subclasses
76
+ sp_default :activity, proc {action_name}
77
+ sp_default :module, proc {controller_name}
78
+ end
79
+
80
+ TODO
81
+ ----
82
+
83
+ * Adapter tests
84
+ * JS client integration
@@ -0,0 +1,9 @@
1
+ module Totango
2
+ class << self; attr_accessor :adapter end
3
+
4
+ class Adapter
5
+ attr_accessor :name, :hook, :action_finder
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,41 @@
1
+ module Totango
2
+ module Adapters
3
+ module Base
4
+ def self.extended(base)
5
+ base.instance_variable_set :@__current_adapter__, Totango::Adapter.new
6
+ end
7
+
8
+ private
9
+
10
+ def included(klass)
11
+ Totango.adapter = adapter
12
+ klass.send(:include, Totango::Resource) unless klass.include?(Totango::Resource)
13
+ (@defaults || []).each do |e|
14
+ klass.sp_default *e
15
+ end
16
+ end
17
+
18
+ def sp_default(k, v)
19
+ @defaults ||= []
20
+ @defaults << [k,v]
21
+ end
22
+
23
+ def register_adapter(name)
24
+ adapter.name = name
25
+ end
26
+
27
+ def hook_method(name)
28
+ adapter.hook = name
29
+ end
30
+
31
+ def action_finder(name)
32
+ adapter.action_finder = name
33
+ end
34
+
35
+ def adapter
36
+ @__current_adapter__
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,15 @@
1
+ module Totango
2
+ module Adapters
3
+ module Merb
4
+ extend Totango::Adapters::Base
5
+
6
+ register_adapter :merb
7
+ hook_method :after
8
+ action_finder :action_name
9
+
10
+ sp_default :activity, proc { action_name }
11
+ sp_default :module, proc { controller_name }
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ module Totango
2
+ module Adapters
3
+ module Rails
4
+ extend Totango::Adapters::Base
5
+
6
+ register_adapter :rails
7
+ hook_method :after_filter
8
+ action_finder :action_name
9
+
10
+ sp_default :activity, proc { action_name }
11
+ sp_default :module, proc { controller_name }
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,60 @@
1
+ module Totango
2
+ class InvalidParamError < StandardError; end
3
+
4
+ class ArgParser
5
+ class <<self
6
+ attr_reader :named_args
7
+
8
+ def parse(args)
9
+ new.tap do |parser|
10
+ args.each do |arg, val|
11
+ param = registered_args[arg]
12
+ raise InvalidParamError, "'#{arg}' does not map to a valid param" unless param
13
+
14
+ parser[param] = val
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def parses_arg(name, *aliases)
22
+ register_named_arg! name
23
+ attr_reader name
24
+
25
+ aliases.unshift(name).each do |argname|
26
+ registered_args[argname] = name
27
+ end
28
+ end
29
+
30
+ def registered_args
31
+ @__registered_args__ ||= {}
32
+ end
33
+
34
+ def register_named_arg!(name)
35
+ @named_args ||= []
36
+ @named_args << name
37
+ end
38
+ end
39
+
40
+ parses_arg :sdr_a, :a, :act, :activity
41
+ parses_arg :sdr_o, :o, :org, :organization
42
+ parses_arg :sdr_m, :m, :mod, :module
43
+ parses_arg :sdr_u, :u, :user
44
+
45
+ def to_params
46
+ ArgParser.named_args.map do |arg|
47
+ [arg, CGI.escape(self[arg].to_s)].join("=")
48
+ end.join("&")
49
+ end
50
+
51
+ def [](arg)
52
+ instance_variable_get :"@#{arg}"
53
+ end
54
+
55
+ def []=(arg, val)
56
+ instance_variable_set :"@#{arg}", val
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,55 @@
1
+ module Totango
2
+ BASE_URI = "http://sdr.totango.com/pixel.gif/?sdr_s=".freeze unless self.const_defined?(:BASE_URI)
3
+
4
+ class NoClientError < StandardError; end
5
+
6
+ class << self
7
+ attr_reader :client
8
+
9
+ def track(data)
10
+ raise NoClientError, "You must set the current client first" unless client
11
+ client.track(data)
12
+ end
13
+
14
+ def srv_id(srv_id)
15
+ @client = Client.new(srv_id)
16
+ end
17
+
18
+ def on?
19
+ Config[:on]
20
+ end
21
+
22
+ def on!
23
+ Config[:on] = true
24
+ end
25
+ end
26
+
27
+ class Client
28
+ def initialize(srv_id)
29
+ @srv_id = srv_id
30
+ end
31
+
32
+ def track(data={})
33
+ url = build_url(data)
34
+
35
+ if Totango.on?
36
+ Thread.new do
37
+ begin
38
+ open(url)
39
+ rescue => e
40
+ STDERR.puts "[Totango] ERROR making call to Totango: #{e.class} ~> #{e.message}"
41
+ end
42
+ end
43
+ else
44
+ unless Config[:suppress_output]
45
+ puts "[Totango] Fake call to #{url}. To make a real call, run Totango.on!"
46
+ end
47
+ end
48
+ end
49
+
50
+ def build_url(data)
51
+ [BASE_URI, @srv_id, "&", ArgParser.parse(data).to_params].join
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,25 @@
1
+ module Totango
2
+ class Config
3
+ class <<self
4
+ def defaults
5
+ @defaults ||= {
6
+ :on => false,
7
+ :suppress_output => false
8
+ }
9
+ end
10
+
11
+ def [](setting)
12
+ defaults[setting]
13
+ end
14
+
15
+ def []=(setting, value)
16
+ defaults[setting] = value
17
+ end
18
+
19
+ def use
20
+ yield defaults
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,80 @@
1
+ module Totango
2
+ class NoAdapterError < StandardError; end
3
+
4
+ module Resource
5
+ @sp_defaults = {
6
+ :organization => "Default Org",
7
+ :user => "Default User",
8
+ :activity => "Default Activity",
9
+ :module => "Default Module"
10
+ }
11
+
12
+ module ClassMethods
13
+ def sp_default(key, val)
14
+ raise ArgumentError, "Key #{key.inspect} is not a valid option" unless @sp_defaults.keys.member?(key)
15
+
16
+ sp_defaults[key] = val
17
+ end
18
+
19
+ # action<Symbol>:: Action to track
20
+ # opts<Hash>:: Override defaults and set conditional tracking
21
+ def track(action, *opts)
22
+ tracker = Totango::Tracker.new(action, *opts)
23
+ sp_trackers << tracker unless sp_trackers.find {|t| t.action.to_s == action.to_s}
24
+ end
25
+
26
+ def sp_trackers
27
+ @__sp_trackers__ ||= []
28
+ end
29
+
30
+ private
31
+
32
+ def inherited(klass)
33
+ super(klass)
34
+ klass.instance_variable_set :@sp_defaults, @sp_defaults.dup
35
+ end
36
+ end
37
+
38
+ def self.included(base)
39
+ base.extend ClassMethods
40
+ class << base; attr_reader :sp_defaults end
41
+ base.instance_variable_set :@sp_defaults, @sp_defaults.dup
42
+ base.send(Totango.adapter.hook, :sp_run)
43
+ end
44
+
45
+ private
46
+
47
+ def sp_run
48
+ raise NoAdapterError, "No adapter has been set" unless Totango.adapter
49
+
50
+ tracker = self.class.sp_trackers.find do |t|
51
+ t.action.to_s == send(Totango.adapter.action_finder).to_s
52
+ end
53
+
54
+ return unless tracker
55
+
56
+ if condition = tracker.opts[:if]
57
+ return unless instance_eval(&condition)
58
+ end
59
+
60
+ Totango.track({
61
+ :o => sp_opt(tracker, :organization),
62
+ :a => sp_opt(tracker, :activity),
63
+ :m => sp_opt(tracker, :module),
64
+ :u => sp_opt(tracker, :user)
65
+ })
66
+ end
67
+
68
+ def sp_opt(tracker, param)
69
+ value = tracker.opts[param] || sp_defaults[param]
70
+
71
+ return instance_eval(&value) if Proc === value
72
+ value
73
+ end
74
+
75
+ def sp_defaults
76
+ self.class.sp_defaults
77
+ end
78
+ end
79
+ end
80
+
@@ -0,0 +1,23 @@
1
+ module Totango
2
+ class Tracker
3
+ def initialize(action, *opts)
4
+ @action = action
5
+ activity = opts.shift
6
+ @opts = opts.empty? ? {} : opts.shift
7
+
8
+ return unless activity
9
+
10
+ case activity
11
+ when String
12
+ @opts[:activity] = activity
13
+ when Hash
14
+ @opts = activity
15
+ else
16
+ raise ArgumentError, "activity must be a String or Hash"
17
+ end
18
+ end
19
+
20
+ attr_reader :action, :opts
21
+ end
22
+ end
23
+
@@ -0,0 +1,3 @@
1
+ module Totango
2
+ VERSION = "0.1.2" unless defined?(::Totango::VERSION)
3
+ end
data/lib/totango.rb ADDED
@@ -0,0 +1,16 @@
1
+ lib = File.expand_path('../../lib/', __FILE__)
2
+ $:.unshift(lib) unless $:.include?(lib)
3
+
4
+ require 'open-uri'
5
+ require 'cgi'
6
+
7
+ require 'totango/config'
8
+ require 'totango/client'
9
+ require 'totango/arg_parser'
10
+ require 'totango/tracker'
11
+ require 'totango/adapter'
12
+ require 'totango/resource'
13
+ require 'totango/adapters/base'
14
+ require 'totango/adapters/merb'
15
+ require 'totango/adapters/rails'
16
+
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubango
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - jonah honeyman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-09 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ description: Enables easy integration of Totango tracking, with options for different ruby web frameworks
34
+ email:
35
+ - jonah@honeyman.org
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/totango/version.rb
44
+ - lib/totango/arg_parser.rb
45
+ - lib/totango/client.rb
46
+ - lib/totango/resource.rb
47
+ - lib/totango/adapters/base.rb
48
+ - lib/totango/adapters/rails.rb
49
+ - lib/totango/adapters/merb.rb
50
+ - lib/totango/adapter.rb
51
+ - lib/totango/tracker.rb
52
+ - lib/totango/config.rb
53
+ - lib/totango.rb
54
+ - LICENSE
55
+ - README.md
56
+ has_rdoc: true
57
+ homepage: https://github.com/jonuts/rubango
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 1
80
+ - 3
81
+ - 6
82
+ version: 1.3.6
83
+ requirements: []
84
+
85
+ rubyforge_project: rubango
86
+ rubygems_version: 1.3.7
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: API wrapper for Totango tracking integration
90
+ test_files: []
91
+