nokogiri-happymapper 0.3.5 → 0.3.6

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.
@@ -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