rubango 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+