legato 0.0.10 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -68,19 +68,19 @@ Here's what google has to say: http://code.google.com/apis/analytics/docs/gdata/
68
68
 
69
69
  Return entries with exits counts greater than or equal to 2000
70
70
 
71
- filter :high_exits, lambda {gte(:exits, 2000)}
71
+ filter :high_exits, &lambda {gte(:exits, 2000)}
72
72
 
73
73
  Return entries with pageview metric less than or equal to 200
74
74
 
75
- filter :low_pageviews, lambda {lte(:pageviews, 200)}
75
+ filter :low_pageviews, &lambda {lte(:pageviews, 200)}
76
76
 
77
77
  Filters with dimensions
78
78
 
79
- filter :for_browser, lambda {|browser| matches(:broswer, browser)}
79
+ filter :for_browser, &lambda {|browser| matches(:browser, browser)}
80
80
 
81
81
  Filters with OR
82
82
 
83
- filter :browsers, lambda {|*browsers| browsers.map {|browser| matches(:broswer, browser)}}
83
+ filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
84
84
 
85
85
 
86
86
  ## Using and Chaining Filters ##
@@ -109,7 +109,7 @@ Be sure to pass the appropriate number of arguments matching the lambda for your
109
109
 
110
110
  For a filter defined like this:
111
111
 
112
- filter :browsers, lambda {|*browsers| browsers.map {|browser| matches(:broswer, browser)}}
112
+ filter :browsers, &lambda {|*browsers| browsers.map {|browser| matches(:browser, browser)}}
113
113
 
114
114
  We can use it like this, passing any number of arguments:
115
115
 
@@ -140,6 +140,45 @@ Operators on dimensions:
140
140
  substring => '=@',
141
141
  not_substring => '!@'
142
142
 
143
+ ## Dynamic Segment
144
+
145
+ Your query can have a dynamic segment, which works with filter expressions. It
146
+ works like an [advanced
147
+ segment](https://support.google.com/analytics/answer/1033017?hl=en), except you
148
+ don't have to create it beforehand, you can just specify it at query time.
149
+
150
+ Some of the numbers you'll get will be different from using a filter, since
151
+ [the subset of visits matched happens before dimensions and metrics are
152
+ calculated](http://ga-dev-tools.appspot.com/explorer/) (hover on the `segment`
153
+ parameter to see).
154
+
155
+ Some metrics and dimensions are not allowed for segments, see the [API
156
+ documentation](https://developers.google.com/analytics/devguides/reporting/core/v3/reference#segment)
157
+ for more details.
158
+
159
+ ### Defining, using and chaining filters
160
+
161
+ Return entries with exits counts greater than or equal to 2000
162
+
163
+ segment :high_exits do
164
+ gte(:exits, 2000)
165
+ end
166
+
167
+ Return entries with pageview metric less than or equal to 200
168
+
169
+ segment :low_pageviews do
170
+ lte(:pageviews, 200)
171
+ end
172
+
173
+ You can chain them
174
+
175
+ Exit.high_exits.low_pageviews(profile)
176
+
177
+ and call them directly on the profile
178
+
179
+ profile.exit.high_exits.low_pageviews
180
+
181
+
143
182
  ## Accounts, WebProperties, Profiles, and Goals ##
144
183
 
145
184
  > Legato::Management::Account.all(user)
data/lib/legato/model.rb CHANGED
@@ -26,6 +26,18 @@ module Legato
26
26
  end
27
27
  end
28
28
 
29
+ def segments
30
+ @segments ||= {}
31
+ end
32
+
33
+ def segment(name, &block)
34
+ segments[name] = block
35
+
36
+ (class << self; self; end).instance_eval do
37
+ define_method(name) {|*args| Query.new(self).apply_segment_filter(*args, &block)}
38
+ end
39
+ end
40
+
29
41
  def set_instance_klass(klass)
30
42
  @instance_klass = klass
31
43
  end
data/lib/legato/query.rb CHANGED
@@ -11,6 +11,12 @@ module Legato
11
11
  end
12
12
  end
13
13
 
14
+ def define_segment_filter(name, &block)
15
+ (class << self; self; end).instance_eval do
16
+ define_method(name) {|*args| apply_segment_filter(*args, &block)}
17
+ end
18
+ end
19
+
14
20
  def self.define_filter_operators(*methods)
15
21
  methods.each do |method|
16
22
  class_eval <<-CODE
@@ -24,12 +30,13 @@ module Legato
24
30
  attr_reader :parent_klass
25
31
  attr_accessor :profile, :start_date, :end_date
26
32
  attr_accessor :sort, :limit, :offset, :quota_user #, :segment # individual, overwritten
27
- attr_accessor :filters # appended to, may add :segments later for dynamic segments
33
+ attr_accessor :filters, :segment_filters # combined, can be appended to
28
34
 
29
35
  def initialize(klass)
30
36
  @loaded = false
31
37
  @parent_klass = klass
32
38
  self.filters = FilterSet.new
39
+ self.segment_filters = FilterSet.new
33
40
  self.start_date = Time.now - MONTH
34
41
  self.end_date = Time.now
35
42
 
@@ -37,10 +44,9 @@ module Legato
37
44
  define_filter(name, &block)
38
45
  end
39
46
 
40
- # may add later for dynamic segments
41
- # klass.segment_definitions.each do |name, segment|
42
- # self.class.define_segment(name, segment)
43
- # end
47
+ klass.segments.each do |name, block|
48
+ define_segment_filter(name, &block)
49
+ end
44
50
  end
45
51
 
46
52
  def instance_klass
@@ -48,6 +54,14 @@ module Legato
48
54
  end
49
55
 
50
56
  def apply_filter(*args, &block)
57
+ apply_filter_expression(self.filters, *args, &block)
58
+ end
59
+
60
+ def apply_segment_filter(*args, &block)
61
+ apply_filter_expression(self.segment_filters, *args, &block)
62
+ end
63
+
64
+ def apply_filter_expression(filter_set, *args, &block)
51
65
  @profile = extract_profile(args)
52
66
 
53
67
  join_character = Legato.and_join_character # filters are joined by AND
@@ -55,7 +69,7 @@ module Legato
55
69
  # # block returns one filter or an array of filters
56
70
  Array.wrap(instance_exec(*args, &block)).each do |filter|
57
71
  filter.join_character ||= join_character # only set when not set explicitly
58
- self.filters << filter
72
+ filter_set << filter
59
73
 
60
74
  join_character = Legato.or_join_character # arrays are joined by OR
61
75
  end
@@ -169,6 +183,10 @@ module Legato
169
183
  @sort = Legato::ListParameter.new(:sort, arr)
170
184
  end
171
185
 
186
+ def segment
187
+ "dynamic::#{segment_filters.to_params}" if segment_filters.any?
188
+ end
189
+
172
190
  # def segment_id
173
191
  # segment.nil? ? nil : "gaid::#{segment}"
174
192
  # end
@@ -184,7 +202,7 @@ module Legato
184
202
  'end-date' => Legato.format_time(end_date),
185
203
  'max-results' => limit,
186
204
  'start-index' => offset,
187
- # 'segment' => segment_id,
205
+ 'segment' => segment,
188
206
  'filters' => filters.to_params, # defaults to AND filtering
189
207
  'fields' => REQUEST_FIELDS,
190
208
  'quotaUser' => quota_user
@@ -1,3 +1,3 @@
1
1
  module Legato
2
- VERSION = "0.0.10"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -69,6 +69,33 @@ describe "Legato::Model" do
69
69
  end
70
70
  end
71
71
 
72
+ context "with segments" do
73
+ before :each do
74
+ @block = lambda {}
75
+ end
76
+
77
+ it 'creates a class method' do
78
+ @model.segment :high, &@block
79
+ @model.respond_to?(:high).should be_true
80
+ end
81
+
82
+ it 'stores the segment' do
83
+ @model.segment :high, &@block
84
+ @model.segments[:high].should == @block
85
+ end
86
+
87
+ it 'returns a Query instance for a segment' do
88
+ query = stub(:apply_segment_filter => "a query")
89
+ Legato::Query.stubs(:new).returns(query)
90
+
91
+ @model.segment :high, &@block
92
+ @model.high('arg1').should == 'a query'
93
+
94
+ Legato::Query.should have_received(:new).with(@model)
95
+ query.should have_received(:apply_segment_filter).with('arg1')
96
+ end
97
+ end
98
+
72
99
  # xit 'has an instance klass'
73
100
  # xit 'sets an instance klass'
74
101
 
@@ -20,6 +20,7 @@ describe Legato::Query do
20
20
  @klass = Class.new
21
21
  @block = lambda {eql(:key, 1000)}
22
22
  @klass.stubs(:filters).returns({:high => @block})
23
+ @klass.stubs(:segments).returns([])
23
24
 
24
25
  @query = Legato::Query.new(@klass)
25
26
  end
@@ -354,6 +355,13 @@ describe Legato::Query do
354
355
  @query.to_params['filters'].should == 'filter set parameters'
355
356
  end
356
357
 
358
+ it 'includes the dynamic segment' do
359
+ segment_filters = stub(:to_params => 'segment parameter', :any? => true)
360
+ @query.stubs(:segment_filters).returns(segment_filters)
361
+
362
+ @query.to_params['segment'].should == 'dynamic::segment parameter'
363
+ end
364
+
357
365
  it 'includes metrics' do
358
366
  metrics = Legato::ListParameter.new(:metrics)
359
367
  metrics.stubs(:to_params).returns({'metrics' => 'pageviews,exits'})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legato
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-07 00:00:00.000000000 Z
12
+ date: 2013-07-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake