Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use JSON instead of XML

  • Loading branch information...
commit 45db83cb6df00ad304fccf5d5921cfe941a7a93e 1 parent 8744473
James Cook authored
View
2  Gemfile
@@ -5,13 +5,13 @@ gem 'rake', '~> 0.8.7'
gem 'i18n'
gem 'activesupport'
-gem 'crack'
group :test do
gem 'shoulda'
gem 'simplecov'
gem 'minitest', :require => false
gem 'jferris-mocha', :require => false
+ gem 'yajl-ruby'
end
group :demo do
View
4 Gemfile.lock
@@ -3,7 +3,6 @@ GEM
remote: http://gems.github.com/
specs:
activesupport (3.0.3)
- crack (0.1.8)
i18n (0.4.2)
jferris-mocha (0.9.8.20100526112143)
rake
@@ -14,13 +13,13 @@ GEM
simplecov (0.3.7)
simplecov-html (>= 0.3.7)
simplecov-html (0.3.9)
+ yajl-ruby (0.8.2)
PLATFORMS
ruby
DEPENDENCIES
activesupport
- crack
i18n
jferris-mocha
minitest
@@ -28,3 +27,4 @@ DEPENDENCIES
rake (~> 0.8.7)
shoulda
simplecov
+ yajl-ruby
View
7 lib/garb.rb
@@ -3,7 +3,12 @@
require 'cgi'
require 'ostruct'
-require 'crack'
+
+begin
+ require 'yajl/json_gem' # JSON.parse
+rescue LoadError
+ require 'json'
+end
begin
require 'active_support/inflector'
View
2  lib/garb/management/feed.rb
@@ -10,7 +10,7 @@ def initialize(session, path)
end
def parsed_response
- @parsed_response ||= Crack::XML.parse(response.body)
+ @parsed_response ||= JSON.parse(response.body)
end
def entries
View
14 lib/garb/report_response.rb
@@ -3,7 +3,7 @@ class ReportResponse
KEYS = ['dxp:metric', 'dxp:dimension']
def initialize(response_body, instance_klass = OpenStruct)
- @xml = response_body
+ @data = response_body
@instance_klass = instance_klass
end
@@ -30,23 +30,23 @@ def parse
end
def entries
- feed? ? [parsed_xml['feed']['entry']].flatten.compact : []
+ feed? ? [parsed_data['feed']['entry']].flatten.compact : []
end
def parse_total_results
- feed? ? parsed_xml['feed']['openSearch:totalResults'].to_i : 0
+ feed? ? parsed_data['feed']['openSearch:totalResults'].to_i : 0
end
def parse_sampled_flag
- feed? ? (parsed_xml['feed']['dxp:containsSampledData'] == 'true') : false
+ feed? ? (parsed_data['feed']['dxp:containsSampledData'] == 'true') : false
end
- def parsed_xml
- @parsed_xml ||= Crack::XML.parse(@xml)
+ def parsed_data
+ @parsed_data ||= JSON.parse(@data)
end
def feed?
- !parsed_xml['feed'].nil?
+ !parsed_data['feed'].nil?
end
def values_for(entry)
View
9 lib/garb/request/data.rb
@@ -3,6 +3,8 @@ module Request
class Data
class ClientError < StandardError; end
+ attr_writer :format
+
def initialize(session, base_url, parameters={})
@session = session
@base_url = base_url
@@ -10,10 +12,15 @@ def initialize(session, base_url, parameters={})
end
def query_string
+ @parameters.merge!("alt" => format) if @parameters.keys.any?
parameter_list = @parameters.map {|k,v| "#{k}=#{v}" }
parameter_list.empty? ? '' : "?#{parameter_list.join('&')}"
end
+ def format
+ @format ||= "json" # TODO Support other formats?
+ end
+
def uri
URI.parse(@base_url)
end
@@ -41,4 +48,4 @@ def oauth_user_request
end
end
end
-end
+end
View
1  test/fixtures/profile_feed.json
@@ -0,0 +1 @@
+{"feed":{"id":"http://www.google.com/analytics/feeds/accounts/blah@gmail.com","updated":"2010-05-06T19:27:28.028-07:00","title":"Profile list for blah@gmail.com","link":{"rel":"self","type":"application/atom+xml","href":"https://www.google.com/analytics/feeds/accounts/default"},"author":{"name":"Google Analytics"},"generator":"Google Analytics","openSearch:totalResults":"2","openSearch:startIndex":"1","openSearch:itemsPerPage":"2","dxp:segment":[{"dxp:definition":null,"id":"gaid::-1","name":"All Visits"},{"dxp:definition":"ga:visitorType==New Visitor","id":"gaid::-2","name":"New Visitors"},{"dxp:definition":"ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==ppc","id":"gaid::-3","name":"Paid Search Traffic"},{"dxp:definition":"ga:city!=New York","id":"gaid::0","name":"Not New York"}],"entry":[{"id":"http://www.google.com/analytics/feeds/accounts/ga:12345","updated":"2008-07-21T14:05:57.000-07:00","title":"Historical","link":{"rel":"alternate","type":"text/html","href":"http://www.google.com/analytics"},"ga:goal":[{"ga:destination":{"caseSensitive":"false","expression":"/blog.html","matchType":"head","step1Required":"false"},"active":"true","name":"Read Blog","number":"1","value":"10.0"},{"ga:destination":{"caseSensitive":"false","expression":"/support.html","matchType":"head","step1Required":"false"},"active":"true","name":"Go for Support","number":"2","value":"5.0"},{"ga:destination":{"ga:step":{"name":"Contact Form Page","number":"1","path":"/contact.html"},"caseSensitive":"false","expression":"/contact-submit","matchType":"exact","step1Required":"true"},"active":"true","name":"Contact Form Submission","number":"3","value":"100.0"},{"ga:destination":{"caseSensitive":"false","expression":"/newsletter-submit","matchType":"exact","step1Required":"false"},"active":"true","name":"Newsletter Form Submission","number":"4","value":"25.0"}],"dxp:property":[{"name":"ga:accountId","value":"1111"},{"name":"ga:accountName","value":"Blog Beta"},{"name":"ga:profileId","value":"1212"},{"name":"ga:webPropertyId","value":"UA-1111-1"},{"name":"ga:currency","value":"USD"},{"name":"ga:timezone","value":"America/New_York"}],"dxp:tableId":"ga:12345","gd:etag":"W/\"CUcHSXs8fip7I2A9WxBUFUg.\"","gd:kind":"analytics#account"},{"id":"http://www.google.com/analytics/feeds/accounts/ga:12346","updated":"2008-11-24T11:51:07.000-08:00","title":"Presently","link":{"rel":"alternate","type":"text/html","href":"http://www.google.com/analytics"},"ga:goal":[{"ga:destination":{"ga:step":{"name":"Contact Form Page","number":"1","path":"/contact.html"},"caseSensitive":"false","expression":"/contact-submit","matchType":"exact","step1Required":"true"},"active":"true","name":"Contact Form Submission","number":"1","value":"100.0"},{"ga:destination":{"caseSensitive":"false","expression":"/newsletter-submit","matchType":"exact","step1Required":"false"},"active":"true","name":"Newsletter Form Submission","number":"2","value":"25.0"}],"dxp:property":[{"name":"ga:accountId","value":"1111"},{"name":"ga:accountName","value":"Blog Beta"},{"name":"ga:profileId","value":"1213"},{"name":"ga:webPropertyId","value":"UA-1111-2"},{"name":"ga:currency","value":"USD"},{"name":"ga:timezone","value":"America/New_York"}],"dxp:tableId":"ga:12346","gd:etag":"W/\"A0UASX45cCp7I2A9WxFQEUQ.\"","gd:kind":"analytics#account"}],"xmlns":"http://www.w3.org/2005/Atom","xmlns:dxp":"http://schemas.google.com/analytics/2009","xmlns:ga":"http://schemas.google.com/ga/2009","xmlns:openSearch":"http://a9.com/-/spec/opensearch/1.1/","xmlns:gd":"http://schemas.google.com/g/2005","gd:etag":"W/\"A0UASX45cCp7I2A9WxFQEUQ.\"","gd:kind":"analytics#accounts"}}
View
1  test/fixtures/report_feed.json
@@ -0,0 +1 @@
+{"feed":{"id":"http://www.google.com/analytics/feeds/data?ids=ga:123456&dimensions=ga:country,ga:city&metrics=ga:pageViews&start-date=2008-01-01&end-date=2008-01-02","updated":"2008-01-02T15:59:59.999-08:00 ","title":"Google Analytics Data for Profile 123456","link":[{"href":"http://www.google.com/analytics/feeds/data","rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml"},{"href":"http://www.google.com/analytics/feeds/data?end-date=2008-01-02&start-date=2008-01-01&metrics=ga%3ApageViews&ids=ga%3A983247&dimensions=ga%3Acountry%2Cga%3Acity","rel":"self","type":"application/atom+xml"},{"href":"http://www.google.com/analytics/feeds/data?start-index=1001&max-results=1000&end-date=2008-01-02&start-date=2008-01-01&metrics=ga%3ApageViews&ids=ga%3A983247&dimensions=ga%3Acountry%2Cga%3Acity","rel":"next","type":"application/atom+xml"}],"author":{"name":"Google Analytics"},"openSearch:startIndex":"3","openSearch:itemsPerPage":"4","openSearch:totalResults":"18","dxp:containsSampledData":"true","ga:webPropertyID":"UA-123456-78","ga:start_date":"2008-01-01","ga:end_date":"2008-01-02","entry":[{"id":" http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=%28not%20set%29&ga:city=%28not%20set%29&start-date=2008-01-01&end-date=2008-01-02 ","updated":" 2008-01-01T16:00:00.001-08:00 ","title":" ga:country=(not set) | ga:city=(not set) ","link":{"href":"http://www.google.com/analytics/feeds/data","rel":"self","type":"application/atom+xml"},"dxp:dimension":[{"name":"ga:country","value":"(not set)"},{"name":"ga:city","value":"(not set)"}],"dxp:metric":{"name":"ga:pageviews","value":"33"}},{"id":" http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=Afghanistan&ga:city=Kabul&start-date=2008-01-01&end-date=2008-01-02 ","updated":" 2008-01-01T16:00:00.001-08:00 ","title":" ga:country=Afghanistan | ga:city=Kabul ","dxp:dimension":[{"name":"ga:country","value":"Afghanistan"},{"name":"ga:city","value":"Kabul"}],"dxp:metric":{"name":"ga:pageviews","value":"2"}},{"id":" http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=Albania&ga:city=Tirana&start-date=2008-01-01&end-date=2008-01-02 ","updated":" 2008-01-01T16:00:00.001-08:00 ","title":" ga:country=Albania | ga:city=Tirana ","dxp:dimension":[{"name":"ga:country","value":"Albania"},{"name":"ga:city","value":"Tirana"}],"dxp:metric":{"name":"ga:pageviews","value":"1"}}],"xmlns":"http://www.w3.org/2005/Atom","xmlns:openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns:dxp":"http://schemas.google.com/analytics/2009","xmlns:ga":"http://schemas.google.com/analytics/2008"}}
View
6 test/unit/garb/management/feed_test.rb
@@ -11,11 +11,11 @@ class FeedTest < MiniTest::Unit::TestCase
end
should "have a parsed response" do
- Crack::XML.stubs(:parse)
+ JSON.stubs(:parse)
@feed.stubs(:response).returns(stub(:body => 'response body'))
@feed.parsed_response
- assert_received(Crack::XML, :parse) {|e| e.with('response body')}
+ assert_received(JSON, :parse) {|e| e.with('response body')}
end
should "have entries from the parsed response" do
@@ -41,4 +41,4 @@ class FeedTest < MiniTest::Unit::TestCase
end
end
end
-end
+end
View
16 test/unit/garb/report_response_test.rb
@@ -7,38 +7,38 @@ class ReportResponseTest < MiniTest::Unit::TestCase
context "A ReportResponse" do
context "with a report feed" do
setup do
- @xml = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.xml"))
+ @json = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.json"))
end
should "parse results from atom xml" do
- response = ReportResponse.new(@xml)
+ response = ReportResponse.new(@json)
assert_equal ['33', '2', '1'], response.results.map(&:pageviews)
end
should "default to returning an array of OpenStruct objects" do
- response = ReportResponse.new(@xml)
+ response = ReportResponse.new(@json)
assert_equal [OpenStruct, OpenStruct, OpenStruct], response.results.map(&:class)
end
should "return an array of instances of a specified class" do
- response = ReportResponse.new(@xml, SpecialKlass)
+ response = ReportResponse.new(@json, SpecialKlass)
assert_equal [SpecialKlass, SpecialKlass, SpecialKlass], response.results.map(&:class)
end
should "know the total number of results" do
- response = ReportResponse.new(@xml)
+ response = ReportResponse.new(@json)
assert_equal 18, response.results.total_results
end
should "know if the data has been sampled" do
- response = ReportResponse.new(@xml)
+ response = ReportResponse.new(@json)
assert_equal true, response.results.sampled?
end
end
should "return an empty array if there are no results" do
- response = ReportResponse.new("result xml")
- Crack::XML.stubs(:parse).with("result xml").returns({'feed' => {'entry' => nil}})
+ response = ReportResponse.new("result json")
+ JSON.stubs(:parse).with("result json").returns({'feed' => {'entry' => nil}})
assert_equal [], response.results.to_a
end
View
8 test/unit/garb/request/data_test.rb
@@ -25,7 +25,7 @@ class DataTest < MiniTest::Unit::TestCase
query_string.sub!(/^\?/, '')
- assert_equal ["ids=12345", "metrics=country"], query_string.split('&').sort
+ assert_equal ["alt=json", "ids=12345", "metrics=country"], query_string.split('&').sort
end
should "return an empty query string if parameters are empty" do
@@ -86,7 +86,7 @@ class DataTest < MiniTest::Unit::TestCase
assert_equal 'responseobject', data_request.oauth_user_request
assert_received(@session, :access_token)
- assert_received(access_token, :get) {|e| e.with('https://example.com/data?key=value', {'GData-Version' => '2'})}
+ assert_received(access_token, :get) {|e| e.with('https://example.com/data?key=value&alt=json', {'GData-Version' => '2'})}
end
should "be able to request via http with an auth token" do
@@ -96,7 +96,7 @@ class DataTest < MiniTest::Unit::TestCase
http = mock do |m|
m.expects(:use_ssl=).with(true)
m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
- m.expects(:get).with('/data?key=value', {
+ m.expects(:get).with('/data?key=value&alt=json', {
'Authorization' => 'GoogleLogin auth=toke',
'GData-Version' => '2'
}).returns(response)
@@ -113,4 +113,4 @@ class DataTest < MiniTest::Unit::TestCase
end
end
-end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.