garb 0.9.1 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +95 -0
  5. data/Gemfile +15 -0
  6. data/README.md +47 -25
  7. data/Rakefile +8 -34
  8. data/garb.gemspec +22 -0
  9. data/lib/garb.rb +71 -48
  10. data/lib/garb/attributes.rb +35 -0
  11. data/lib/garb/core_ext/array.rb +13 -0
  12. data/lib/garb/core_ext/string.rb +48 -0
  13. data/lib/garb/core_ext/symbol.rb +59 -0
  14. data/lib/garb/destination.rb +5 -6
  15. data/lib/garb/errors.rb +20 -0
  16. data/lib/garb/filter_parameters.rb +20 -29
  17. data/lib/garb/management/account.rb +10 -16
  18. data/lib/garb/management/feed.rb +4 -5
  19. data/lib/garb/management/goal.rb +10 -15
  20. data/lib/garb/management/profile.rb +11 -20
  21. data/lib/garb/management/segment.rb +9 -15
  22. data/lib/garb/management/web_property.rb +11 -16
  23. data/lib/garb/model.rb +37 -13
  24. data/lib/garb/path_attribute.rb +7 -0
  25. data/lib/garb/report_parameter.rb +5 -5
  26. data/lib/garb/report_response.rb +29 -28
  27. data/lib/garb/reports/bounces.rb +1 -1
  28. data/lib/garb/reports/exits.rb +1 -1
  29. data/lib/garb/reports/pageviews.rb +1 -1
  30. data/lib/garb/reports/unique_pageviews.rb +1 -1
  31. data/lib/garb/reports/visits.rb +1 -1
  32. data/lib/garb/request/authentication.rb +54 -0
  33. data/lib/garb/request/data.rb +98 -0
  34. data/lib/garb/result_set.rb +23 -9
  35. data/lib/garb/session.rb +3 -3
  36. data/lib/garb/step.rb +4 -4
  37. data/lib/garb/support.rb +6 -0
  38. data/lib/garb/version.rb +3 -3
  39. data/test/fixtures/account_management.json +1 -0
  40. data/test/fixtures/ga_profile_management.json +1 -0
  41. data/test/fixtures/ga_segment_management.json +1 -0
  42. data/test/fixtures/ga_webproperty_management.json +1 -0
  43. data/test/fixtures/goal_management.json +1 -0
  44. data/test/fixtures/profile_feed.json +1 -0
  45. data/test/fixtures/report_feed.json +75 -0
  46. data/test/test_helper.rb +6 -10
  47. data/test/unit/garb/filter_parameters_test.rb +15 -46
  48. data/test/unit/garb/management/account_test.rb +8 -16
  49. data/test/unit/garb/management/feed_test.rb +5 -10
  50. data/test/unit/garb/management/goal_test.rb +7 -21
  51. data/test/unit/garb/management/profile_test.rb +11 -26
  52. data/test/unit/garb/management/segment_test.rb +7 -6
  53. data/test/unit/garb/management/web_property_test.rb +10 -12
  54. data/test/unit/garb/model_test.rb +70 -32
  55. data/test/unit/garb/report_parameter_test.rb +6 -6
  56. data/test/unit/garb/report_response_test.rb +23 -13
  57. data/test/unit/garb/request/authentication_test.rb +152 -0
  58. data/test/unit/garb/request/data_test.rb +157 -0
  59. data/test/unit/garb/session_test.rb +13 -13
  60. data/test/unit/garb_test.rb +4 -11
  61. data/test/unit/symbol_operator_test.rb +3 -3
  62. metadata +90 -292
  63. data/lib/garb/account.rb +0 -22
  64. data/lib/garb/account_feed_request.rb +0 -25
  65. data/lib/garb/authentication_request.rb +0 -53
  66. data/lib/garb/data_request.rb +0 -42
  67. data/lib/garb/goal.rb +0 -20
  68. data/lib/garb/profile.rb +0 -33
  69. data/lib/garb/report.rb +0 -28
  70. data/lib/garb/resource.rb +0 -115
  71. data/lib/support.rb +0 -40
  72. data/test/unit/garb/account_feed_request_test.rb +0 -42
  73. data/test/unit/garb/account_test.rb +0 -53
  74. data/test/unit/garb/authentication_request_test.rb +0 -121
  75. data/test/unit/garb/coverage/assets/0.3.9/app.js +0 -66
  76. data/test/unit/garb/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  77. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  78. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  79. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  80. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  81. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  82. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  83. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  84. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  85. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  86. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  87. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  88. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  89. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  90. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  91. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  92. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  93. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  94. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  95. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  96. data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
  97. data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
  98. data/test/unit/garb/coverage/assets/0.3.9/favicon.png +0 -0
  99. data/test/unit/garb/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
  100. data/test/unit/garb/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
  101. data/test/unit/garb/coverage/assets/0.3.9/jquery.timeago.js +0 -141
  102. data/test/unit/garb/coverage/assets/0.3.9/jquery.url.js +0 -174
  103. data/test/unit/garb/coverage/assets/0.3.9/loading.gif +0 -0
  104. data/test/unit/garb/coverage/assets/0.3.9/magnify.png +0 -0
  105. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  106. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  107. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  108. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  109. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  110. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  111. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  112. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  113. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  114. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  115. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  116. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  117. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  118. data/test/unit/garb/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
  119. data/test/unit/garb/coverage/assets/0.3.9/stylesheet.css +0 -341
  120. data/test/unit/garb/coverage/index.html +0 -100
  121. data/test/unit/garb/coverage/resultset.yml +0 -5
  122. data/test/unit/garb/data_request_test.rb +0 -107
  123. data/test/unit/garb/destination_test.rb +0 -28
  124. data/test/unit/garb/goal_test.rb +0 -24
  125. data/test/unit/garb/management/coverage/assets/0.3.9/app.js +0 -66
  126. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  127. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  128. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  129. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  130. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  131. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  132. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  133. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  134. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  135. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  136. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  137. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  138. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  139. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  140. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  141. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  142. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  143. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  144. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  145. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  146. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
  147. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
  148. data/test/unit/garb/management/coverage/assets/0.3.9/favicon.png +0 -0
  149. data/test/unit/garb/management/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
  150. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
  151. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.timeago.js +0 -141
  152. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.url.js +0 -174
  153. data/test/unit/garb/management/coverage/assets/0.3.9/loading.gif +0 -0
  154. data/test/unit/garb/management/coverage/assets/0.3.9/magnify.png +0 -0
  155. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  156. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  157. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  158. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  159. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  160. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  161. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  162. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  163. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  164. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  165. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  166. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  167. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  168. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
  169. data/test/unit/garb/management/coverage/assets/0.3.9/stylesheet.css +0 -341
  170. data/test/unit/garb/management/coverage/index.html +0 -100
  171. data/test/unit/garb/management/coverage/resultset.yml +0 -5
  172. data/test/unit/garb/profile_test.rb +0 -77
  173. data/test/unit/garb/report_test.rb +0 -99
  174. data/test/unit/garb/resource_test.rb +0 -50
  175. data/test/unit/garb/step_test.rb +0 -15
@@ -0,0 +1,35 @@
1
+ module Garb
2
+ module Attributes
3
+ def self.extended(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def ga_attribute(*keys)
9
+ hashes, symbols = keys.partition { |k| k.is_a? Hash }
10
+ symbols.each { |key| define_a_method_for key }
11
+ hashes.each { |hash| map_values_for hash }
12
+ end
13
+
14
+ private
15
+ def define_a_method_for(key, custom_key = nil)
16
+ custom_key ||= key.to_s.camelize(:lower)
17
+ define_method(key) do
18
+ var = "@#{key}"
19
+ if instance_variable_defined? var
20
+ instance_variable_get var
21
+ else
22
+ hash_key = (custom_key || key).to_s
23
+ instance_variable_set var, @entry[hash_key]
24
+ end
25
+ end #unless method_defined?(key)
26
+ end
27
+
28
+ def map_values_for(hash)
29
+ hash.each_pair do |key, value|
30
+ define_a_method_for key, value
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ unless Object.const_defined?('ActiveSupport')
2
+ class Array
3
+ def self.wrap(object)
4
+ if object.nil?
5
+ []
6
+ elsif object.respond_to?(:to_ary)
7
+ object.to_ary
8
+ else
9
+ [object]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ # Pull in some AS String utilities (not loaded if AS is available)
2
+ unless Object.const_defined?('ActiveSupport')
3
+ class String
4
+ def camelize(first_letter = :upper)
5
+ case first_letter
6
+ when :upper then Garb::Inflector.camelize(self, true)
7
+ when :lower then Garb::Inflector.camelize(self, false)
8
+ end
9
+ end
10
+ alias_method :camelcase, :camelize
11
+
12
+ def underscore
13
+ Garb::Inflector.underscore(self)
14
+ end
15
+
16
+ def demodulize
17
+ Garb::Inflector.demodulize(self)
18
+ end
19
+ end
20
+
21
+ module Garb
22
+ module Inflector
23
+ extend self
24
+
25
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
26
+ if first_letter_in_uppercase
27
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
28
+ else
29
+ lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
30
+ end
31
+ end
32
+
33
+ def underscore(camel_cased_word)
34
+ word = camel_cased_word.to_s.dup
35
+ word.gsub!(/::/, '/')
36
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
37
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
38
+ word.tr!("-", "_")
39
+ word.downcase!
40
+ word
41
+ end
42
+
43
+ def demodulize(class_name_in_module)
44
+ class_name_in_module.to_s.gsub(/^.*::/, '')
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,59 @@
1
+ module SymbolOperatorMethods
2
+ OPERATORS = {
3
+ :eql => '==',
4
+ :not_eql => '!=',
5
+ :gt => '>',
6
+ :gte => '>=',
7
+ :lt => '<',
8
+ :lte => '<=',
9
+ :matches => '==',
10
+
11
+ :does_not_match => '!=',
12
+ :contains => '=~',
13
+ :does_not_contain => '!~',
14
+ :substring => '=@',
15
+ :not_substring => '!@',
16
+
17
+ :desc => '-',
18
+ :descending => '-'
19
+ }
20
+ SLUGS = OPERATORS.keys.freeze
21
+
22
+ def to_google_analytics
23
+ t = Garb.to_google_analytics @field || @target
24
+ o = OPERATORS[@operator]
25
+
26
+ [:desc, :descending].include?(@operator) ? "#{o}#{t}" : "#{t}#{o}"
27
+ end
28
+ end
29
+
30
+ class SymbolOperator
31
+ include SymbolOperatorMethods
32
+
33
+ def initialize(field, operator)
34
+ @field, @operator = field, operator
35
+ end unless method_defined? :initialize
36
+ end
37
+
38
+ symbol_slugs = if Object.const_defined?('DataMapper')
39
+ # make sure the class is defined
40
+ require 'dm-core/core_ext/symbol'
41
+
42
+ # add to_google_analytics to DM's Opeartor
43
+ class DataMapper::Query::Operator
44
+ include SymbolOperatorMethods
45
+ end
46
+
47
+ SymbolOperatorMethods::SLUGS - DataMapper::Query::Conditions::Comparison.slugs
48
+ else
49
+ SymbolOperatorMethods::SLUGS
50
+ end
51
+
52
+ # define the remaining symbol operators
53
+ symbol_slugs.each do |operator|
54
+ Symbol.class_eval <<-RUBY
55
+ def #{operator}
56
+ SymbolOperator.new self, :#{operator}
57
+ end unless method_defined? :#{operator}
58
+ RUBY
59
+ end
@@ -1,18 +1,17 @@
1
1
  module Garb
2
2
  class Destination
3
- attr_reader :match_type, :expression, :steps, :case_sensitive
3
+ attr_reader :match_type, :url, :steps, :case_sensitive
4
4
 
5
5
  alias :case_sensitive? :case_sensitive
6
6
 
7
7
  def initialize(attributes)
8
- return unless attributes.is_a?(Hash)
8
+ return unless attributes.is_a? Hash
9
9
 
10
10
  @match_type = attributes['matchType']
11
- @expression = attributes['expression']
12
- @case_sensitive = (attributes['caseSensitive'] == 'true')
11
+ @url = attributes['url'] # TODO was @expression
12
+ @case_sensitive = attributes['caseSensitive']
13
13
 
14
- step_attributes = attributes[Garb.to_ga('step')]
15
- @steps = Array(step_attributes.is_a?(Hash) ? [step_attributes] : step_attributes).map {|s| Step.new(s)}
14
+ @steps = attributes['steps'] && attributes['steps'].map { |s| Step.new(s) }
16
15
  end
17
16
  end
18
17
  end
@@ -0,0 +1,20 @@
1
+ module Garb
2
+ class Error < StandardError; end
3
+ class MissingCertFileError < Error; end
4
+ class AuthError < Error; end
5
+ class ClientError < Error
6
+ attr_reader :code, :message, :errors, :uri
7
+
8
+ def initialize(uri, message, code = nil, errors = [])
9
+ @code, @message, @errors, @uri = code, message, errors, uri
10
+ end
11
+
12
+ def to_s
13
+ "#{code ? "[#{code}] #{message}" : message} : #{uri}"
14
+ end
15
+ end
16
+ class BadRequestError < ClientError; end
17
+ class InvalidCredentialsError < ClientError; end
18
+ class InsufficientPermissionsError < ClientError; end
19
+ class BackendError < ClientError; end
20
+ end
@@ -1,42 +1,33 @@
1
1
  module Garb
2
2
  class FilterParameters
3
- def self.define_operators(*methods)
4
- methods.each do |method|
5
- class_eval <<-CODE
6
- def #{method}(field, value)
7
- @filter_hash.merge!({SymbolOperator.new(field, :#{method}) => value})
8
- end
9
- CODE
10
- end
11
- end
12
-
13
- define_operators :eql, :not_eql, :gt, :gte, :lt, :lte, :matches,
14
- :does_not_match, :contains, :does_not_contain, :substring, :not_substring
15
-
16
3
  attr_accessor :parameters
17
4
 
18
- def initialize
19
- self.parameters = []
5
+ def initialize(parameters)
6
+ self.parameters = (Array.wrap(parameters) || []).compact
20
7
  end
21
8
 
22
- def filters(&block)
23
- @filter_hash = {}
24
-
25
- instance_eval &block
26
-
27
- self.parameters << @filter_hash
9
+ def to_params
10
+ value = array_to_params(self.parameters)
11
+ value.empty? ? {} : {'filters' => value}
28
12
  end
29
13
 
30
- def to_params
31
- value = self.parameters.map do |param|
32
- param.map do |k,v|
33
- next unless k.is_a?(SymbolOperator)
34
- escaped_v = v.to_s.gsub(/([,;\\])/) {|c| '\\'+c}
35
- "#{URI.encode(k.to_google_analytics, /[=<>]/)}#{CGI::escape(escaped_v)}"
36
- end.join('%3B') # Hash AND (no duplicate keys), escape char for ';' fixes oauth
14
+ private
15
+ def array_to_params(arr)
16
+ arr.map do |param|
17
+ case param
18
+ when Hash then hash_to_params(param)
19
+ when Array then array_to_params(param)
20
+ end
37
21
  end.join(',') # Array OR
22
+ end
38
23
 
39
- value.empty? ? {} : {'filters' => value}
24
+ def hash_to_params(hsh)
25
+ hsh.map do |k, v|
26
+ next unless k.is_a?(SymbolOperatorMethods)
27
+
28
+ escaped_v = v.to_s.gsub(/([,;])/) { |c| '\\' + c }
29
+ "#{URI.encode(k.to_google_analytics, /[=<>]/)}#{CGI::escape(escaped_v)}"
30
+ end.join('%3B') # Hash AND (no duplicate keys), escape char for ';' fixes oauth
40
31
  end
41
32
  end
42
33
  end
@@ -1,26 +1,20 @@
1
1
  module Garb
2
2
  module Management
3
3
  class Account
4
- attr_accessor :session, :path
5
- attr_accessor :id, :title, :name
4
+ extend Garb::Attributes
5
+ include PathAttribute
6
6
 
7
- def self.all(session = Session)
8
- feed = Feed.new(session, '/accounts')
9
- feed.entries.map {|entry| new_from_entry(entry, session)}
10
- end
7
+ attr_reader :session
8
+ ga_attribute :id, :name
11
9
 
12
- def self.new_from_entry(entry, session)
13
- account = new
14
- account.session = session
15
- account.path = Garb.parse_link(entry, "self").gsub(Feed::BASE_URL, '')
16
- account.title = entry['title'].gsub('Google Analytics Account ', '') # can we get this in properties=?
17
- account.properties = Garb.parse_properties(entry)
18
- account
10
+ def initialize(entry, session)
11
+ @entry = entry
12
+ @session = session
19
13
  end
20
14
 
21
- def properties=(properties)
22
- self.id = properties["account_id"]
23
- self.name = properties["account_name"]
15
+ def self.all(session = Session)
16
+ feed = Feed.new(session, '/accounts')
17
+ feed.entries.map { |entry| new(entry, session) }
24
18
  end
25
19
 
26
20
  def web_properties
@@ -1,21 +1,20 @@
1
1
  module Garb
2
2
  module Management
3
3
  class Feed
4
- BASE_URL = "https://www.google.com/analytics/feeds/datasources/ga"
4
+ BASE_URL = 'https://www.googleapis.com/analytics/v3/management'
5
5
 
6
6
  attr_reader :request
7
7
 
8
8
  def initialize(session, path)
9
- @request = DataRequest.new(session, BASE_URL+path)
9
+ @request = Request::Data.new(session, BASE_URL + path)
10
10
  end
11
11
 
12
12
  def parsed_response
13
- @parsed_response ||= Crack::XML.parse(response.body)
13
+ @parsed_response ||= MultiJson.load(response.body)
14
14
  end
15
15
 
16
16
  def entries
17
- # possible to have nil entries, yuck
18
- parsed_response ? [parsed_response['feed']['entry']].flatten.compact : []
17
+ parsed_response && parsed_response['items'] || []
19
18
  end
20
19
 
21
20
  def response
@@ -1,15 +1,17 @@
1
1
  module Garb
2
2
  module Management
3
3
  class Goal
4
+ extend Attributes
5
+ include PathAttribute
4
6
 
5
- attr_accessor :session, :path
6
- attr_accessor :name, :number, :value, :destination, :active
7
+ attr_reader :session
8
+ ga_attribute :name, :number, :value, :active
7
9
 
8
10
  alias :active? :active
9
11
 
10
12
  def self.all(session = Session, path = '/accounts/~all/webproperties/~all/profiles/~all/goals')
11
13
  feed = Feed.new(session, path)
12
- feed.entries.map {|entry| new_from_entry(entry, session)}
14
+ feed.entries.map { |entry| new(entry, session) }
13
15
  end
14
16
 
15
17
  def self.for_account(account)
@@ -24,20 +26,13 @@ module Garb
24
26
  all(profile.session, profile.path + '/goals')
25
27
  end
26
28
 
27
- def self.new_from_entry(entry, session)
28
- goal = new
29
- goal.session = session
30
- goal.path = Garb.parse_link(entry, "self").gsub(Feed::BASE_URL, '')
31
- goal.properties = entry[Garb.to_ga('goal')]
32
- goal
29
+ def initialize(entry, session)
30
+ @entry = entry
31
+ @session = session
33
32
  end
34
33
 
35
- def properties=(properties)
36
- self.name = properties["name"]
37
- self.number = properties["number"].to_i
38
- self.value = properties["value"].to_f
39
- self.active = (properties["active"] == "true")
40
- self.destination = Destination.new(properties[Garb.to_ga('destination')])
34
+ def destination
35
+ @destination ||= Destination.new(@entry['urlDestinationDetails'])
41
36
  end
42
37
  end
43
38
  end
@@ -3,41 +3,32 @@ module Garb
3
3
  class Profile
4
4
 
5
5
  include ProfileReports
6
+ include PathAttribute
7
+ extend Attributes
6
8
 
7
- attr_accessor :session, :path
8
- attr_accessor :id, :table_id, :title, :account_id, :web_property_id
9
+ attr_reader :session
10
+ ga_attribute :id, :name, :account_id, :web_property_id, :website_url
9
11
 
10
12
  def self.all(session = Session, path = '/accounts/~all/webproperties/~all/profiles')
11
13
  feed = Feed.new(session, path)
12
- feed.entries.map {|entry| new_from_entry(entry, session)}
14
+ feed.entries.map { |entry| new(entry, session) }
13
15
  end
14
16
 
15
17
  def self.for_account(account)
16
- all(account.session, account.path+'/webproperties/~all/profiles')
18
+ all(account.session, account.path + '/webproperties/~all/profiles')
17
19
  end
18
20
 
19
21
  def self.for_web_property(web_property)
20
- all(web_property.session, web_property.path+'/profiles')
22
+ all(web_property.session, web_property.path + '/profiles')
21
23
  end
22
24
 
23
- def self.new_from_entry(entry, session)
24
- profile = new
25
- profile.session = session
26
- profile.path = Garb.parse_link(entry, "self").gsub(Feed::BASE_URL, '')
27
- profile.properties = Garb.parse_properties(entry)
28
- profile
29
- end
30
-
31
- def properties=(properties)
32
- self.id = properties['profile_id']
33
- self.table_id = properties['dxp:table_id']
34
- self.title = properties['profile_name']
35
- self.account_id = properties['account_id']
36
- self.web_property_id = properties['web_property_id']
25
+ def initialize(entry, session)
26
+ @entry = entry
27
+ @session = session
37
28
  end
38
29
 
39
30
  def goals
40
- Goal.for_profile(self)
31
+ Goal.for_profile self
41
32
  end
42
33
  end
43
34
  end
@@ -1,26 +1,20 @@
1
1
  module Garb
2
2
  module Management
3
3
  class Segment
4
- attr_accessor :session, :path
5
- attr_accessor :id, :name, :definition
4
+ extend Attributes
5
+ include PathAttribute
6
+
7
+ attr_reader :session
8
+ ga_attribute :name, :definition, :id => 'segmentId'
6
9
 
7
10
  def self.all(session = Session)
8
11
  feed = Feed.new(session, '/segments')
9
- feed.entries.map {|entry| new_from_entry(entry, session)}
10
- end
11
-
12
- def self.new_from_entry(entry, session)
13
- segment = new
14
- segment.session = session
15
- segment.path = Garb.parse_link(entry, "self").gsub(Feed::BASE_URL, '')
16
- segment.properties = entry['dxp:segment']
17
- segment
12
+ feed.entries.map { |entry| new(entry, session) }
18
13
  end
19
14
 
20
- def properties=(properties)
21
- self.id = properties['id']
22
- self.name = properties['name']
23
- self.definition = properties['dxp:definition']
15
+ def initialize(entry, session)
16
+ @entry = entry
17
+ @session = session
24
18
  end
25
19
  end
26
20
  end