statwhore 0.0.3

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/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ * 0.0.3 - updated to new google api and switched to rspec
2
+ * 0.0.2 - switched to googlebase for google auth and requests
3
+ * 0.0.1 - initial relase
data/License.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007 John Nunemaker
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.
data/Manifest.txt ADDED
@@ -0,0 +1,31 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/statwhore.rb
9
+ lib/statwhore/connection.rb
10
+ lib/statwhore/google.rb
11
+ lib/statwhore/google/analytics.rb
12
+ lib/statwhore/google/analytics/account.rb
13
+ lib/statwhore/google/analytics/profile.rb
14
+ lib/statwhore/google/feedburner.rb
15
+ lib/statwhore/version.rb
16
+ log/debug.log
17
+ script/destroy
18
+ script/generate
19
+ script/txt2html
20
+ setup.rb
21
+ spec/fixtures/analytics_account_find_all.html
22
+ spec/fixtures/analytics_profile_find_all.html
23
+ spec/fixtures/dashboard_report_webgroup.xml
24
+ spec/spec.opts
25
+ spec/spec_helper.rb
26
+ spec/statwhore_google_analytics_account_spec.rb
27
+ spec/statwhore_google_analytics_profile_spec.rb
28
+ spec/statwhore_google_analytics_spec.rb
29
+ tasks/deployment.rake
30
+ tasks/environment.rake
31
+ tasks/website.rake
data/README.txt ADDED
@@ -0,0 +1,4 @@
1
+ = WARNING!!!!!!!!!!!
2
+ This is completely unstable and will remain so for a bit. Do not use it right now unless you are hoping for things to go boom. :)
3
+
4
+ Feel free however to hack at it and send me patches.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/config/hoe.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'statwhore/version'
2
+
3
+ AUTHOR = 'FIXME full name' # can also be an array of Authors
4
+ EMAIL = "FIXME email"
5
+ DESCRIPTION = "description of gem"
6
+ GEM_NAME = 'statwhore' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'statwhore' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Statwhore::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'statwhore documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
62
+ p.extra_deps = [ ['googlebase', '>= 0.2.0'], ['activesupport', '>= 2.0.2'], ['hpricot', '>= 0.6'] ]
63
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
64
+
65
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
66
+
67
+ end
68
+
69
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'statwhore'
@@ -0,0 +1,38 @@
1
+ require 'net/https'
2
+ module Statwhore
3
+ class Connection
4
+ def initialize(base_url, args = {})
5
+ @base_url = base_url
6
+ @username = args[:username]
7
+ @password = args[:password]
8
+ end
9
+
10
+ def get(resource, args = nil)
11
+ request(resource, "get", args)
12
+ end
13
+
14
+ def post(resource, args = nil)
15
+ request(resource, "post", args)
16
+ end
17
+
18
+ def request(resource, method = "get", args = nil)
19
+ url = URI.join(@base_url, resource)
20
+ url.query = args.map { |k,v| "%s=%s" % [URI.encode(k.to_s), URI.encode(v.to_s)] }.join("&") if args
21
+
22
+ case method
23
+ when "get"
24
+ req = Net::HTTP::Get.new(url.request_uri)
25
+ when "post"
26
+ req = Net::HTTP::Post.new(url.request_uri)
27
+ end
28
+
29
+ req.basic_auth(@username, @password) if @username && @password
30
+
31
+ http = Net::HTTP.new(url.host, url.port)
32
+ http.use_ssl = (url.port == 443)
33
+
34
+ res = http.start() { |conn| conn.request(req) }
35
+ res.body
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ module Statwhore
2
+ module Google
3
+ module Analytics
4
+ class Account < ::Google::Base
5
+ def self.find_all
6
+ doc = Hpricot::XML(get('https://www.google.com:443/analytics/home/'))
7
+ (doc/'select[@name=account_list] option').inject([]) do |accounts, option|
8
+ account_id = option['value'].to_i
9
+ accounts << new(:account_id => account_id, :name => option.inner_html) if account_id > 0
10
+ accounts
11
+ end
12
+ end
13
+
14
+ attr_accessor :name, :account_id
15
+
16
+ def initialize(attrs)
17
+ @name = attrs[:name]
18
+ @account_id = attrs[:account_id]
19
+ end
20
+
21
+ def profiles(force=false)
22
+ if force || @profiles.nil?
23
+ @profiles = Profile.find_all(account_id)
24
+ end
25
+ @profiles
26
+ end
27
+
28
+ def to_s
29
+ "#{name} (#{account_id})"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ module Statwhore
2
+ module Google
3
+ module Analytics
4
+ class Profile < ::Google::Base
5
+ def self.find_all(account_id)
6
+ doc = Hpricot::XML(get("https://www.google.com:443/analytics/home/admin?scid=#{account_id}"))
7
+ (doc/'select[@name=profile_list] option').inject([]) do |profiles, option|
8
+ profile_id = option['value'].to_i
9
+ profiles << Profile.new(:account_id => account_id, :profile_id => profile_id, :name => option.inner_html) if profile_id > 0
10
+ profiles
11
+ end
12
+ end
13
+
14
+ def self.find(account_id, profile_id)
15
+ find_all(account_id).detect { |p| p.profile_id.to_s == profile_id.to_s }
16
+ end
17
+
18
+ attr_accessor :account_id, :name, :profile_id
19
+
20
+ def initialize(attrs)
21
+ raise ArgumentError, ":profile_id is required" unless attrs.has_key?(:profile_id)
22
+ @account_id = attrs[:account_id] if attrs.has_key?(:account_id)
23
+ @name = attrs[:name] if attrs.has_key?(:name)
24
+ @profile_id = attrs[:profile_id] if attrs.has_key?(:profile_id)
25
+ end
26
+
27
+ def report(options={})
28
+ options.reverse_merge!({
29
+ :report => 'Dashboard',
30
+ :from => Time.now.utc - 7.days,
31
+ :to => Time.now.utc,
32
+ :tab => 0,
33
+ :format => FORMAT_XML,
34
+ :compute => 'average',
35
+ :view => 0
36
+ })
37
+ options[:from] = ensure_datetime_in_google_format(options[:from])
38
+ options[:to] = ensure_datetime_in_google_format(options[:to])
39
+
40
+ params = {
41
+ :pdr => "#{options[:from]}-#{options[:to]}",
42
+ :rpt => "#{options[:report]}Report",
43
+ :cmp => options[:compute],
44
+ :fmt => options[:format],
45
+ :view => options[:view],
46
+ :tab => options[:tab],
47
+ :id => profile_id,
48
+ }
49
+ self.class.get("https://google.com/analytics/reporting/export", :query_hash => params)
50
+ end
51
+
52
+ def pageviews(options={})
53
+ response = report(options.merge({:report => 'Dashboard'}))
54
+ doc = Hpricot::XML(response)
55
+ pageviews = (doc/:ItemSummary).detect { |summary| summary.at('Message').inner_html == 'Pageviews' }
56
+ pageviews && pageviews.at('SummaryValue') ? pageviews.at('SummaryValue').inner_html.gsub(/\D/, '').to_i : 0
57
+ end
58
+
59
+ def visits(options={})
60
+ response = report(options.merge({:report => 'Dashboard'}))
61
+ doc = Hpricot::XML(response)
62
+ pageviews = (doc/:ItemSummary).detect { |summary| summary.at('Message').inner_html == 'Visits' }
63
+ pageviews && pageviews.at('SummaryValue') ? pageviews.at('SummaryValue').inner_html.gsub(/\D/, '').to_i : 0
64
+ end
65
+
66
+ # takes a Date, Time or String
67
+ def ensure_datetime_in_google_format(time)
68
+ time.is_a?(Time) || time.is_a?(Date) ? time.strftime('%Y%m%d') : time
69
+ end
70
+
71
+ def to_s
72
+ "#{name} (#{profile_id})"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/analytics/account'
2
+ require File.dirname(__FILE__) + '/analytics/profile'
3
+
4
+ module Statwhore
5
+ module Google
6
+ module Analytics
7
+ FORMAT_PDF = '0'
8
+ FORMAT_XML = '1'
9
+ FORMAT_CSV = '2'
10
+ FORMAT_TAB = '3'
11
+
12
+ VALID_REPORTS = %w[ Dashboard ]
13
+
14
+ class InvalidCredentials < Exception; end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ module Statwhore
2
+ module Google
3
+ module Feedburner
4
+ API_URL = 'http://api.feedburner.com/management/1.0'
5
+
6
+ class Base
7
+ def self.establish_connection(u, p)
8
+ @@connection = Connection.new(API_URL, u, p)
9
+ end
10
+
11
+ def self.connection
12
+ @@connection
13
+ end
14
+ end
15
+
16
+ class Feed < Base
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ #
24
+ # include Statwhore::Google
25
+ # Feedburner::Feed.find(:all)
26
+ # Feedburner::Feed.find('johnnunemaker')
27
+ # Feedburner::Feed.find(1234)
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/google/analytics'
2
+ require File.dirname(__FILE__) + '/google/feedburner'
@@ -0,0 +1,9 @@
1
+ module Statwhore #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 3
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/statwhore.rb ADDED
@@ -0,0 +1,16 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'uri'
6
+ require 'ostruct'
7
+ require 'rubygems'
8
+ gem 'hpricot', '>= 0.6'
9
+ require 'hpricot'
10
+ gem 'activesupport', '>= 2.0.2'
11
+ require 'activesupport'
12
+ gem 'googlebase', '>= 0.2.0'
13
+ require 'google/base'
14
+
15
+ require File.dirname(__FILE__) + '/statwhore/google'
16
+ require File.dirname(__FILE__) + '/statwhore/connection'
data/log/debug.log ADDED
File without changes
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
data/script/txt2html ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ begin
5
+ require 'newgem'
6
+ rescue LoadError
7
+ puts "\n\nGenerating the website requires the newgem RubyGem"
8
+ puts "Install: gem install newgem\n\n"
9
+ exit(1)
10
+ end
11
+ require 'redcloth'
12
+ require 'syntax/convertors/html'
13
+ require 'erb'
14
+ require File.dirname(__FILE__) + '/../lib/statwhore/version.rb'
15
+
16
+ version = Statwhore::VERSION::STRING
17
+ download = 'http://rubyforge.org/projects/statwhore'
18
+
19
+ class Fixnum
20
+ def ordinal
21
+ # teens
22
+ return 'th' if (10..19).include?(self % 100)
23
+ # others
24
+ case self % 10
25
+ when 1: return 'st'
26
+ when 2: return 'nd'
27
+ when 3: return 'rd'
28
+ else return 'th'
29
+ end
30
+ end
31
+ end
32
+
33
+ class Time
34
+ def pretty
35
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
36
+ end
37
+ end
38
+
39
+ def convert_syntax(syntax, source)
40
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
41
+ end
42
+
43
+ if ARGV.length >= 1
44
+ src, template = ARGV
45
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')
46
+
47
+ else
48
+ puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
49
+ exit!
50
+ end
51
+
52
+ template = ERB.new(File.open(template).read)
53
+
54
+ title = nil
55
+ body = nil
56
+ File.open(src) do |fsrc|
57
+ title_text = fsrc.readline
58
+ body_text = fsrc.read
59
+ syntax_items = []
60
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
61
+ ident = syntax_items.length
62
+ element, syntax, source = $1, $2, $3
63
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
64
+ "syntax-temp-#{ident}"
65
+ }
66
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
67
+ body = RedCloth.new(body_text).to_html
68
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
69
+ end
70
+ stat = File.stat(src)
71
+ created = stat.ctime
72
+ modified = stat.mtime
73
+
74
+ $stdout << template.result(binding)