nokogiri-happymapper 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,6 +12,8 @@ module HappyMapper
12
12
  def self.included(base)
13
13
  base.instance_variable_set("@attributes", {})
14
14
  base.instance_variable_set("@elements", {})
15
+ base.instance_variable_set("@registered_namespaces", {})
16
+
15
17
  base.extend ClassMethods
16
18
  end
17
19
 
@@ -27,6 +29,10 @@ module HappyMapper
27
29
  @attributes[to_s] || []
28
30
  end
29
31
 
32
+ def register_namespace(namespace, ns)
33
+ @registered_namespaces.merge!({namespace => ns})
34
+ end
35
+
30
36
  def element(name, type, options={})
31
37
  element = Element.new(name, type, options)
32
38
  @elements[to_s] ||= []
@@ -93,6 +99,7 @@ module HappyMapper
93
99
  namespaces = options[:namespaces]
94
100
  namespaces ||= {}
95
101
  namespaces = namespaces.merge(xml.collect_namespaces) if xml.respond_to?(:collect_namespaces)
102
+ namespaces = namespaces.merge(@registered_namespaces)
96
103
 
97
104
  if namespaces.has_key?("xmlns")
98
105
  namespace ||= DEFAULT_NS
@@ -0,0 +1,127 @@
1
+ <feed xmlns='http://www.w3.org/2005/Atom' xmlns:dxp='http://schemas.google.com/analytics/2009' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/&quot;CU4CSXo_cCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#accounts'>
2
+ <id>http://www.google.com/analytics/feeds/accounts/someuser@gmail.com</id>
3
+ <updated>2010-12-20T19:59:28.448-08:00</updated>
4
+ <title>Profile list for someuser@gmail.com</title>
5
+ <link rel='self' type='application/atom+xml' href='https://www.google.com/analytics/feeds/accounts/default'/>
6
+ <author>
7
+ <name>Google Analytics</name>
8
+ </author>
9
+ <generator version='1.0'>Google Analytics</generator>
10
+ <openSearch:totalResults>9</openSearch:totalResults>
11
+ <openSearch:startIndex>1</openSearch:startIndex>
12
+ <openSearch:itemsPerPage>9</openSearch:itemsPerPage>
13
+ <dxp:segment id='gaid::-1' name='All Visits'>
14
+ <dxp:definition> </dxp:definition>
15
+ </dxp:segment>
16
+ <dxp:segment id='gaid::-2' name='New Visitors'>
17
+ <dxp:definition>ga:visitorType==New Visitor</dxp:definition>
18
+ </dxp:segment>
19
+ <dxp:segment id='gaid::-3' name='Returning Visitors'>
20
+ <dxp:definition>ga:visitorType==Returning Visitor</dxp:definition>
21
+ </dxp:segment>
22
+ <dxp:segment id='gaid::-4' name='Paid Search Traffic'>
23
+ <dxp:definition>ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==ppc</dxp:definition>
24
+ </dxp:segment>
25
+ <dxp:segment id='gaid::-5' name='Non-paid Search Traffic'>
26
+ <dxp:definition>ga:medium==organic</dxp:definition>
27
+ </dxp:segment>
28
+ <dxp:segment id='gaid::-6' name='Search Traffic'>
29
+ <dxp:definition>ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==organic,ga:medium==ppc</dxp:definition>
30
+ </dxp:segment>
31
+ <dxp:segment id='gaid::-7' name='Direct Traffic'>
32
+ <dxp:definition>ga:medium==(none)</dxp:definition>
33
+ </dxp:segment>
34
+ <dxp:segment id='gaid::-8' name='Referral Traffic'>
35
+ <dxp:definition>ga:medium==referral</dxp:definition>
36
+ </dxp:segment>
37
+ <dxp:segment id='gaid::-9' name='Visits with Conversions'>
38
+ <dxp:definition>ga:goalCompletionsAll&gt;0</dxp:definition>
39
+ </dxp:segment>
40
+ <dxp:segment id='gaid::-10' name='Visits with Transactions'>
41
+ <dxp:definition>ga:transactions&gt;0</dxp:definition>
42
+ </dxp:segment>
43
+ <dxp:segment id='gaid::-11' name='Mobile Traffic'>
44
+ <dxp:definition>ga:isMobile==Yes</dxp:definition>
45
+ </dxp:segment>
46
+ <dxp:segment id='gaid::-12' name='Non-bounce Visits'>
47
+ <dxp:definition>ga:bounces==0</dxp:definition>
48
+ </dxp:segment>
49
+ <entry gd:etag='W/&quot;CkENQXs9fip7I2A9Wx5SE0w.&quot;' gd:kind='analytics#account'>
50
+ <id>http://www.google.com/analytics/feeds/accounts/ga:123456</id>
51
+ <updated>2010-08-08T16:38:10.566-07:00</updated>
52
+ <title>www.homedepot.com</title>
53
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
54
+ <dxp:property name='ga:accountId' value='254087'/>
55
+ <dxp:property name='ga:accountName' value='www.homechefdepot.com'/>
56
+ <dxp:property name='ga:profileId' value='123456'/>
57
+ <dxp:property name='ga:webPropertyId' value='UA-254087-1'/>
58
+ <dxp:property name='ga:currency' value='USD'/>
59
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
60
+ <dxp:tableId>ga:123456</dxp:tableId>
61
+ </entry>
62
+ <entry gd:etag='W/&quot;C0YESXcyfyp7I2A9Wx9SFkU.&quot;' gd:kind='analytics#account'>
63
+ <id>http://www.google.com/analytics/feeds/accounts/ga:8575980</id>
64
+ <updated>2010-12-06T16:18:28.997-08:00</updated>
65
+ <title>www.pda.org</title>
66
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
67
+ <dxp:property name='ga:accountId' value='4277553'/>
68
+ <dxp:property name='ga:accountName' value='www.pdma.org'/>
69
+ <dxp:property name='ga:profileId' value='8575980'/>
70
+ <dxp:property name='ga:webPropertyId' value='UA-4277553-1'/>
71
+ <dxp:property name='ga:currency' value='USD'/>
72
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
73
+ <dxp:tableId>ga:8575980</dxp:tableId>
74
+ </entry>
75
+ <entry gd:etag='W/&quot;CU4CSXo_cCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#account'>
76
+ <id>http://www.google.com/analytics/feeds/accounts/ga:25620226</id>
77
+ <updated>2010-12-20T19:59:28.448-08:00</updated>
78
+ <title>business.com</title>
79
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
80
+ <dxp:property name='ga:accountId' value='12312214'/>
81
+ <dxp:property name='ga:accountName' value='business.com'/>
82
+ <dxp:property name='ga:profileId' value='25620226'/>
83
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
84
+ <dxp:property name='ga:currency' value='USD'/>
85
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
86
+ <dxp:tableId>ga:25620226</dxp:tableId>
87
+ </entry>
88
+ <entry gd:etag='W/&quot;CU4CSX0yfCp7I2A9Wx9RGU0.&quot;' gd:kind='analytics#account'>
89
+ <id>http://www.google.com/analytics/feeds/accounts/ga:12123131</id>
90
+ <updated>2010-12-20T19:59:28.394-08:00</updated>
91
+ <title>blog.com</title>
92
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
93
+ <dxp:property name='ga:accountId' value='12312214'/>
94
+ <dxp:property name='ga:accountName' value='business.com'/>
95
+ <dxp:property name='ga:profileId' value='12123131'/>
96
+ <dxp:property name='ga:webPropertyId' value='UA-12345678-1'/>
97
+ <dxp:property name='ga:currency' value='USD'/>
98
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
99
+ <dxp:tableId>ga:12123131</dxp:tableId>
100
+ </entry>
101
+ <entry gd:etag='W/&quot;DUMNQHk_fSp7I2A9Wx5bEE4.&quot;' gd:kind='analytics#account'>
102
+ <id>http://www.google.com/analytics/feeds/accounts/ga:37685582</id>
103
+ <updated>2010-10-25T13:11:31.745-07:00</updated>
104
+ <title>The Social</title>
105
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
106
+ <dxp:property name='ga:accountId' value='12312214'/>
107
+ <dxp:property name='ga:accountName' value='business.com'/>
108
+ <dxp:property name='ga:profileId' value='37685582'/>
109
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
110
+ <dxp:property name='ga:currency' value='USD'/>
111
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
112
+ <dxp:tableId>ga:37685582</dxp:tableId>
113
+ </entry>
114
+ <entry gd:etag='W/&quot;DE8HR3o4eCp7I2A9Wx5UF0w.&quot;' gd:kind='analytics#account'>
115
+ <id>http://www.google.com/analytics/feeds/accounts/ga:38132423</id>
116
+ <updated>2010-10-21T20:07:16.430-07:00</updated>
117
+ <title>Skyline</title>
118
+ <link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
119
+ <dxp:property name='ga:accountId' value='12312214'/>
120
+ <dxp:property name='ga:accountName' value='business.com'/>
121
+ <dxp:property name='ga:profileId' value='38132423'/>
122
+ <dxp:property name='ga:webPropertyId' value='UA-12312214-1'/>
123
+ <dxp:property name='ga:currency' value='USD'/>
124
+ <dxp:property name='ga:timezone' value='America/Los_Angeles'/>
125
+ <dxp:tableId>ga:38132423</dxp:tableId>
126
+ </entry>
127
+ </feed>
@@ -12,6 +12,41 @@ module Analytics
12
12
  attribute :value, String
13
13
  end
14
14
 
15
+ class Goal
16
+ include HappyMapper
17
+
18
+ # Google Analytics does a dirtry trick where a user with no goals
19
+ # returns a profile without any goals data or the declared namespace
20
+ # which means Nokogiri does not pick up the namespace automatically.
21
+ # To fix this, we manually register the namespace to avoid bad XPath
22
+ # expression. Dirty, but works.
23
+
24
+ register_namespace 'ga', 'http://schemas.google.com/ga/2009'
25
+ namespace 'ga'
26
+
27
+ tag 'goal'
28
+ attribute :active, Boolean
29
+ attribute :name, String
30
+ attribute :number, Integer
31
+ attribute :value, Float
32
+
33
+ def clean_name
34
+ name.gsub(/ga:/, '')
35
+ end
36
+ end
37
+
38
+ class Profile
39
+ include HappyMapper
40
+
41
+ tag 'entry'
42
+ element :title, String
43
+ element :tableId, String, :namespace => 'dxp'
44
+
45
+ has_many :properties, Property
46
+ has_many :goals, Goal
47
+ end
48
+
49
+
15
50
  class Entry
16
51
  include HappyMapper
17
52
 
@@ -687,6 +722,16 @@ describe HappyMapper do
687
722
  property.value.should == '85301'
688
723
  end
689
724
 
725
+ it "should be able to parse google analytics profile xml with manually declared namespace" do
726
+ data = Analytics::Profile.parse(fixture_file('analytics_profile.xml'))
727
+ data.entries.size.should == 6
728
+
729
+ entry = data.entries[0]
730
+ entry.title.should == 'www.homedepot.com'
731
+ entry.properties.size.should == 6
732
+ entry.goals.size.should == 0
733
+ end
734
+
690
735
  it "should allow instantiating with a string" do
691
736
  module StringFoo
692
737
  class Bar
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 5
9
- version: 0.3.5
8
+ - 6
9
+ version: 0.3.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Damien Le Berrigaud
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-12-21 00:00:00 +01:00
21
+ date: 2010-12-23 00:00:00 +01:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -32,8 +32,8 @@ dependencies:
32
32
  segments:
33
33
  - 1
34
34
  - 4
35
- - 0
36
- version: 1.4.0
35
+ - 2
36
+ version: 1.4.2
37
37
  type: :runtime
38
38
  version_requirements: *id001
39
39
  - !ruby/object:Gem::Dependency
@@ -46,9 +46,9 @@ dependencies:
46
46
  - !ruby/object:Gem::Version
47
47
  segments:
48
48
  - 1
49
- - 2
50
- - 9
51
- version: 1.2.9
49
+ - 3
50
+ - 0
51
+ version: 1.3.0
52
52
  type: :development
53
53
  version_requirements: *id002
54
54
  description: Object to XML Mapping Library, using Nokogiri (fork from John Nunemaker's Happymapper)
@@ -71,6 +71,7 @@ files:
71
71
  - spec/fixtures/address.xml
72
72
  - spec/fixtures/ambigous_items.xml
73
73
  - spec/fixtures/analytics.xml
74
+ - spec/fixtures/analytics_profile.xml
74
75
  - spec/fixtures/commit.xml
75
76
  - spec/fixtures/current_weather.xml
76
77
  - spec/fixtures/dictionary.xml
@@ -129,6 +130,7 @@ test_files:
129
130
  - spec/fixtures/address.xml
130
131
  - spec/fixtures/ambigous_items.xml
131
132
  - spec/fixtures/analytics.xml
133
+ - spec/fixtures/analytics_profile.xml
132
134
  - spec/fixtures/commit.xml
133
135
  - spec/fixtures/current_weather.xml
134
136
  - spec/fixtures/dictionary.xml