gnip_api 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 934f7c386beafd72012565bdf098cf5aeffd02cc
4
- data.tar.gz: d8c9cb19d9be2588c2a4e778e6404fa0beefd70d
3
+ metadata.gz: 4a0f89ada9f7ec8c66ff45982702e37a0649e8ff
4
+ data.tar.gz: 65a52d03b722a14f6264c8d51086d3df9e24cdf9
5
5
  SHA512:
6
- metadata.gz: d7b13598a821df13c084e8eff061b758eaaed773cd7839efac4a08c193fecc271f77fff06873659d594a11079fa918293624e824aa333d7925aefab086541a26
7
- data.tar.gz: d2466cfe6c98b44e2f7efdcfe69b422e439671bbcd9d411145ca414ac8b5bd4240fb8e96be19968e4986c818d09fdb568b536d4dcfeddc21ab0cbe9b570bbe09
6
+ metadata.gz: 1560448fb7366e1422971587abb31fbfe16c121faaf28d37f7cdfcd7aa81019b05d789e053c4ce3be7f20bd67e23d15bc9d46bde9cd9e0ddd226b5f2805f887f
7
+ data.tar.gz: c4750dbfcae74f230df1b4a93099b1786715ce5a92fb1b60ad844ba221d7ec75549d37d43e5cf7f113f7e25db8e7a2fe7eb9e54d484b965011038f9dda1090b1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gnip_api (0.0.3)
4
+ gnip_api (0.0.5)
5
5
  activesupport
6
6
  addressable
7
7
  httparty
data/README.md CHANGED
@@ -1,13 +1,23 @@
1
+ ### Important: Gnip will be ending support for v1 endpoints on December 1 of 2016. GnipApi will be updated to work with v2, backward compatibility won't be posible after the deadline.
2
+
1
3
  # GnipApi
2
4
 
3
5
  Connect with different Gnip APIs and get data from streams.
4
6
 
7
+ ## Recent Changes
8
+
9
+ - Removed unused RateLimiter
10
+ - Removed unused Mutex
11
+ - Added source and label to config as default values
12
+ - Added Search API
13
+ - All APIs now default their parameters from config, you can still call an API with different label or source
14
+ - More docs
15
+
5
16
  ## Notes
6
17
 
7
- - Can't access Search API currently
8
- - Rules endpoint are now rate limited.
9
- - A simple rate limiter was implemented.
10
- - You can configure the gem's mutex outside the gem if you plan to have concurrency. Very experimental for now.
18
+ - Search api will be added for v2 endpoints
19
+ - V2 endpoints for stream will be implemented before deadline
20
+ - RateLimiter and Mutex dropped due to lack of usage
11
21
 
12
22
  ## Installation
13
23
 
@@ -36,7 +46,8 @@ GnipApi.configure |config|
36
46
  config.account = 'myGnipAccount' # Your accounts name
37
47
  config.adapter_class = SomeAdapter # You can define your own adapter, more in the following section
38
48
  config.logger = Logger.new('myLog.log') # You can also provide a custom logger
39
- config.mutex = Mutex.new # Experimental thread safety, more below
49
+ config.source = 'twitter' # General source, if none defined when quering, this will be used
50
+ config.label = 'mystream' # General stream label, if none defined when quering, this will be used
40
51
  end
41
52
  ```
42
53
 
@@ -44,22 +55,101 @@ Put the avobe code in a initializer if you're using Rails, or somewhere else if
44
55
 
45
56
  Note that you'll need a source and a label. Source is the data source within Gnip, such as Twitter, and label is the identifier of your stream.
46
57
 
47
- ### Adapters
58
+ ### Search API
48
59
 
49
- GnipApi is not dependent of a single adapter (there's a dependency with HTTParty, but shhh... it won't last too long). You can use one of the provided adapters, or you can make your own, using the BaseAdapter class. You only need to implement the desired connector POST, GET and DELETE methods. There's an extra stream_get method, but it's just a variant of GET.
60
+ The Search API allows you to get counts or activities in a time period, with a maximum period size of 30 days per request. PowerTrack rules are used as query parameter, but be careful *PowerTrack operators may not be supporter on Search API or could behave differently*. Read the Gnip docs to make sure.
61
+ To access the Search API you will need a rule first, you can use PowerTrack Rule object for it:
50
62
 
51
- The custom adapter does not require to live within the gem files, as long as GnipApi has access to your class, just put it in the config and you're ready to go. See the current adapters for reference.
63
+ ```ruby
64
+ rule = GnipApi::Apis::PowerTrack::Rule.new :value => 'keyword1 OR keyword2'
65
+ end
66
+ ```
52
67
 
53
- ### Mutex and Thread Safety
68
+ Then you can query the search endpoint. *Only counts are available currently*.
54
69
 
55
- GnipApi has this feature in experimental stage, using a simple mutex to interact with the RateLimiter. The limiters are very simple, and should prevent your code executing more requests than it should. Depending where you are defining the mutex, you can elevate the coverage. GnipApi only requires an instance of Mutex, which you can place somewhere else for it to use.
70
+ ```ruby
71
+ results = GnipApi::Apis::Search.new.counts :rule => rule
72
+ end
73
+ ```
56
74
 
57
- ## WIP State
75
+ You can set different parameters:
76
+
77
+ ```ruby
78
+ results = GnipApi::Apis::Search.new.counts :rule => rule, :from_date => DateTime.parse('2016-01-01 00:00'), :to_date => DateTime.parse('2016-05-01 22:00'), :bucket => 'day'
79
+ end
80
+ ```
81
+
82
+ When you query for more than 30 days, the results will include a :next token to iterate over the remaining pages. You can instantly feed this token to a following request with same parameters:
83
+
84
+ ```ruby
85
+ results = GnipApi::Apis::Search.new.counts :rule => rule, :from_date => DateTime.parse('2016-01-01 00:00'), :to_date => DateTime.parse('2016-05-01 22:00'), :bucket => 'day', :next_token => 'token_from_previous_request'
86
+ end
87
+ ```
88
+
89
+ ### PowerTrack
90
+
91
+ PowerTrack API has various functions. You can upload, delete and get rules and you can stream the activities. To create rules you need to create the rule objects:
92
+
93
+ ```ruby
94
+ rules = []
95
+ rules << GnipApi::Apis::PowerTrack::Rule.new :value => 'keyword1 OR keyword2', :tag => 'first_rule'
96
+ rules << GnipApi::Apis::PowerTrack::Rule.new :value => 'keyword3 keyword4', :tag => 'second_rule'
97
+ end
98
+ ```
99
+
100
+ Once you have your rule objects set, you can put them into an array and feed them to the PowerTrack Rules API:
58
101
 
59
- GnipApi is still a WIP. Call it a beta, alpha, gem that has part of the features, whatever. Thing is, that it is currently usable. The custom adapter feature is there, and some of the APIs of Gnip were implemented. I'll be coding more things into this, such as other APIs, more limiters, request retries, error handling, different adapters for known connectors like RestClient or HTTP/net, etc.
102
+ ```ruby
103
+ GnipApi::Apis::PowerTrack::Rules.new.create rules
104
+ end
105
+ ```
106
+
107
+ That will upload the rules to the stream. The endpoint doesn't return anything on success but it will validate rules before applying and any syntax error will be raised as an error.
108
+
109
+ To get a list of rules defined in the stream:
110
+
111
+ ```ruby
112
+ GnipApi::Apis::PowerTrack::Rules.new.list
113
+ end
114
+ ```
115
+
116
+ That will return an array of GnipRule::Apis::PowerTrack::Rule objects. In the same way as the upload the delete method removes 1 or more rules:
117
+
118
+ ```ruby
119
+ GnipApi::Apis::PowerTrack::Rules.new.delete rules
120
+ end
121
+ ```
60
122
 
123
+ Same as upload, no response from Gnip when deleting.
124
+ Finally, you can stream the activities and do something with them:
125
+
126
+ ```ruby
127
+ GnipApi::Apis::PowerTrack::Stream.new.consume do |messages|
128
+ messages.select{|m| m.activity?}.each{|a| puts a.body}
129
+ messages.select{|m| m.system_message?}.each{|s| puts s.message}
130
+ end
131
+ ```
132
+
133
+ There are a few considerations to make when doing this:
134
+
135
+ - Gnip closes stream sometimes, either for operational reasons or because you can't handle the volume of data
136
+ - System messages include compliance notifications you should follow if you save the data locally
137
+ - Be careful when putting this into a daemon, closing the stream can be tricky given how this was done
138
+ - I've experience issues with a Zlib error that I currently couldn't debug and fix, if you build a daemon for this, be sure to code restart procedures
139
+
140
+ ### Adapters
141
+
142
+ GnipApi is not dependent of a single adapter (there's a dependency with HTTParty, but shhh... it won't last too long). You can use one of the provided adapters, or you can make your own, using the BaseAdapter class. You only need to implement the desired connector POST, GET and DELETE methods. There's an extra stream_get method, but it's just a variant of GET. Keep in mind that Gnip uses compression, I found out that Excon doesn't decompress responses by default, just to name an example.
143
+ The custom adapter does not require to live within the gem files, as long as GnipApi has access to your class, just put it in the config and you're ready to go. See the current adapters for reference.
144
+
145
+ ## WIP State
146
+
147
+ GnipApi is a WIP. Call it a beta, alpha, gem that has part of the features, whatever. It is currently usable and it's being used by... well.. me. The custom adapter feature is there, and some of the APIs of Gnip were implemented. I'll be coding more things into this, such as other APIs, request retries, error handling, different adapters for known connectors like RestClient or HTTP/net, etc.
61
148
  In any case, you were warned about it. Feel free to fill my issues list on Github :)
62
149
 
150
+ ## Gnip documentation for reference
151
+
152
+ [http://support.gnip.com/](http://support.gnip.com/)
63
153
 
64
154
  ## Contributing
65
155
 
@@ -13,13 +13,12 @@ module GnipApi
13
13
  # - source: which data source to use (I think only twitter is available)
14
14
  def initialize params={}
15
15
  @adapter = GnipApi::Adapter.new
16
- @label = params[:label]
17
- @source = params[:source]
16
+ @label = params[:label] || GnipApi.config.label
17
+ @source = params[:source] || GnipApi.config.source
18
18
  end
19
19
 
20
20
  # Returns an array of defined rules
21
21
  def list
22
- request_allowed?
23
22
  request = create_get_request
24
23
  rules = adapter.get(request)
25
24
  parse_rules(rules)
@@ -29,7 +28,6 @@ module GnipApi
29
28
  # - rules: GnipApi::Apis::PowerTrack::Rule object
30
29
  def create rules
31
30
  raise GnipApi::Errors::PowerTrack::MissingRules.new if rules.nil? || rules.empty?
32
- request_allowed?
33
31
  request = create_post_request(construct_rules(rules))
34
32
  adapter.post(request)
35
33
  end
@@ -38,7 +36,6 @@ module GnipApi
38
36
  # - rules: GnipApi::Apis::PowerTrack::Rule object
39
37
  def delete rules
40
38
  raise GnipApi::Errors::PowerTrack::MissingRules.new if rules.nil? || rules.empty?
41
- request_allowed?
42
39
  request = create_delete_request(construct_rules(rules))
43
40
  adapter.delete(request)
44
41
  end
@@ -75,9 +72,6 @@ module GnipApi
75
72
  GnipApi::Request.new_delete(endpoint, payload)
76
73
  end
77
74
 
78
- def request_allowed?
79
- raise 'RateLimited' unless GnipApi.config.rate_limiter.rules_request_allowed?
80
- end
81
75
  end
82
76
  end
83
77
  end
@@ -5,8 +5,8 @@ module GnipApi
5
5
  attr_reader :adapter
6
6
 
7
7
  def initialize params = {}
8
- @stream = params[:stream]
9
- @source = params[:source]
8
+ @stream = params[:stream] || GnipApi.config.label
9
+ @source = params[:source] || GnipApi.config.source
10
10
  set_config
11
11
  end
12
12
 
@@ -0,0 +1,69 @@
1
+ # Gnip Search Full Archive API
2
+ #
3
+ # Retrive counts with a provided rule
4
+
5
+ module GnipApi
6
+ module Apis
7
+ class Search
8
+ attr_reader :adapter
9
+
10
+ def initialize params={}
11
+ @adapter = GnipApi::Adapter.new
12
+ @label = params[:label] || GnipApi.config.label
13
+ end
14
+
15
+ def counts options={}
16
+ required_options?(options)
17
+ payload = construct_counts_payload(options)
18
+ request = GnipApi::Request.new_post(count_endpoint, payload)
19
+ data = adapter.post(request)
20
+ return parse_counts_response(data)
21
+ end
22
+
23
+ private
24
+ def count_endpoint
25
+ GnipApi::Endpoints.search_counts(@label)
26
+ end
27
+
28
+ def required_options
29
+ [:rule]
30
+ end
31
+
32
+ def required_options? options
33
+ provided_options = required_options - options.keys
34
+ raise GnipApi::Errors::Search::MissingParameters.new(provided_options) if provided_options.any?
35
+ end
36
+
37
+ def parse_date date
38
+ return nil unless date
39
+ date.strftime('%Y%m%d%H%M')
40
+ end
41
+
42
+ def parse_counts_response data
43
+ parsed_data = JSON.parse(data)
44
+ result_set = parsed_data['results']
45
+ params = parsed_data['requestParameters']
46
+ result = {:results => [], :total_count => parsed_data['totalCount'], :next => parsed_data['next'], :request_parameters => {}}
47
+ result[:request_parameters][:bucket] = params['bucket'] if params['bucket']
48
+ result[:request_parameters][:from_date] = Time.parse("#{params['fromDate']}-0000") if params['fromDate']
49
+ result[:request_parameters][:to_date] = Time.parse("#{params['toDate']}-0000") if params['toDate']
50
+ result_set.each do |item|
51
+ result[:results] << {:time_period => Time.parse("#{item['timePeriod']}-0000"), :count => item['count']}
52
+ end
53
+ return result
54
+ end
55
+
56
+ def construct_counts_payload options
57
+ payload = {
58
+ :query => options[:rule].value,
59
+ :fromDate => parse_date(options[:from_date]),
60
+ :toDate => parse_date(options[:to_date]),
61
+ :bucket => options[:bucket],
62
+ :next => options[:next_token]
63
+ }
64
+ payload.delete_if{|k,v| v.nil?}
65
+ return payload.to_json
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,13 +1,10 @@
1
1
  module GnipApi
2
2
  class Configuration
3
- attr_accessor :user, :password, :adapter_class, :account, :logger, :mutex
4
- attr_reader :rate_limiter
3
+ attr_accessor :user, :password, :adapter_class, :account, :logger, :source, :label
5
4
 
6
5
  def initialize
7
6
  @adapter_class = GnipApi::Adapters::HTTPartyAdapter
8
7
  @logger = Logger.new('tmp/gnip_api.log')
9
- @mutex = Mutex.new
10
- @rate_limiter = GnipApi::RateLimiter.new
11
8
  end
12
9
  end
13
10
  end
@@ -9,12 +9,12 @@ module GnipApi
9
9
  URI("https://stream.gnip.com:443/accounts/#{account}/publishers/#{source}/streams/track/#{label}.json")
10
10
  end
11
11
 
12
- def search_stream label
13
- URI("https://search.gnip.com/accounts/#{account}/search/#{label}.json")
12
+ def search_activities label
13
+ URI("https://gnip-api.twitter.com/search/fullarchive/accounts/#{account}/#{label}")
14
14
  end
15
15
 
16
- def search_count
17
- URI("https://search.gnip.com/accounts/#{ CONFIG['account'] }/search/#{label}.json/counts")
16
+ def search_counts label
17
+ URI("https://gnip-api.twitter.com/search/fullarchive/accounts/#{account}/#{label}/counts.json")
18
18
  end
19
19
 
20
20
  private
@@ -16,6 +16,14 @@ module GnipApi
16
16
  end
17
17
  end
18
18
 
19
+ module Search
20
+ class MissingParameters < StandardError
21
+ def initialize missing_params
22
+ @message = "Missing required parameters: #{missing_params}"
23
+ end
24
+ end
25
+ end
26
+
19
27
  class MissingCredentials < StandardError
20
28
  def initialize
21
29
  @message = 'No credentials provided'
@@ -1,3 +1,3 @@
1
1
  module GnipApi
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/gnip_api.rb CHANGED
@@ -2,16 +2,11 @@ require "gnip_api/version"
2
2
  require "gnip_api/errors"
3
3
  require "gnip_api/configuration"
4
4
  require "gnip_api/endpoints"
5
- require "gnip_api/limiters/rules"
6
- require "gnip_api/rate_limiter"
7
5
  require "gnip_api/apis/power_track/stream"
8
6
  require "gnip_api/apis/power_track/rules"
9
7
  require "gnip_api/apis/power_track/buffer"
10
8
  require "gnip_api/apis/power_track/rule"
11
- require "gnip_api/apis/search/stream"
12
- require "gnip_api/apis/search/count"
13
- require "gnip_api/apis/search/query"
14
- require "gnip_api/apis/search/result"
9
+ require "gnip_api/apis/search"
15
10
  require "gnip_api/gnip/message"
16
11
  require "gnip_api/gnip/system_message"
17
12
  require "gnip_api/gnip/actor"
@@ -48,10 +43,6 @@ module GnipApi
48
43
  self.configuration.logger
49
44
  end
50
45
 
51
- def rate_limiter
52
- self.configuration.rate_limiter
53
- end
54
-
55
46
  def config
56
47
  self.configuration
57
48
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe GnipApi::Apis::Search do
4
+ describe '.new' do
5
+ it 'creates search instance' do
6
+ object = GnipApi::Apis::Search.new
7
+ expect(object).not_to eq(nil)
8
+ expect(object.class).to eq(GnipApi::Apis::Search)
9
+ end
10
+ end
11
+
12
+ describe '#counts' do
13
+ before do
14
+ @api = GnipApi::Apis::Search.new
15
+ allow(@api.adapter).to receive(:post).and_return("{\"results\":[{\"timePeriod\":\"201607200000\",\"count\":87},{\"timePeriod\":\"201607190000\",\"count\":188}],\"totalCount\":5949,\"requestParameters\":{\"bucket\":\"day\",\"fromDate\":\"201607190000\",\"toDate\":\"201608181340\"}}")
16
+ end
17
+
18
+ it 'raises error if missing params' do
19
+ expect(Proc.new{@api.counts}).to raise_error(GnipApi::Errors::Search::MissingParameters)
20
+ end
21
+
22
+ it 'performs request and parses response' do
23
+ rule = GnipApi::Apis::PowerTrack::Rule.new :value => 'lolcat OR madcat'
24
+ result = @api.counts :rule => rule
25
+ expect(result).not_to eq(nil)
26
+ expect(result.keys).to eq([:results, :total_count, :next, :request_parameters])
27
+ end
28
+ end
29
+ end
@@ -10,6 +10,8 @@ describe GnipApi::Configuration do
10
10
  expect(config.account).to eq(nil)
11
11
  expect(config.adapter_class).to eq(GnipApi::Adapters::HTTPartyAdapter)
12
12
  expect(config.logger).not_to eq(nil)
13
+ expect(config.source).to eq(nil)
14
+ expect(config.label).to eq(nil)
13
15
  end
14
16
  end
15
17
 
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,8 @@ def configure_gem
9
9
  config.password = "lolcat"
10
10
  config.account = "something"
11
11
  config.adapter_class = TestAdapter
12
+ config.source = 'twitter'
13
+ config.label = 'prod'
12
14
  end
13
15
  end
14
16
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gnip_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rayko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-14 00:00:00.000000000 Z
11
+ date: 2016-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -175,10 +175,7 @@ files:
175
175
  - lib/gnip_api/apis/power_track/rule.rb
176
176
  - lib/gnip_api/apis/power_track/rules.rb
177
177
  - lib/gnip_api/apis/power_track/stream.rb
178
- - lib/gnip_api/apis/search/count.rb
179
- - lib/gnip_api/apis/search/query.rb
180
- - lib/gnip_api/apis/search/result.rb
181
- - lib/gnip_api/apis/search/stream.rb
178
+ - lib/gnip_api/apis/search.rb
182
179
  - lib/gnip_api/configuration.rb
183
180
  - lib/gnip_api/endpoints.rb
184
181
  - lib/gnip_api/errors.rb
@@ -188,8 +185,6 @@ files:
188
185
  - lib/gnip_api/gnip/message.rb
189
186
  - lib/gnip_api/gnip/system_message.rb
190
187
  - lib/gnip_api/gnip/url.rb
191
- - lib/gnip_api/limiters/rules.rb
192
- - lib/gnip_api/rate_limiter.rb
193
188
  - lib/gnip_api/request.rb
194
189
  - lib/gnip_api/response.rb
195
190
  - lib/gnip_api/version.rb
@@ -223,12 +218,12 @@ files:
223
218
  - spec/gnip_api/apis/power_track/rule_spec.rb
224
219
  - spec/gnip_api/apis/power_track/rules_spec.rb
225
220
  - spec/gnip_api/apis/power_track/stream_spec.rb
221
+ - spec/gnip_api/apis/search_spec.rb
226
222
  - spec/gnip_api/configuration_spec.rb
227
223
  - spec/gnip_api/endpoints_spec.rb
228
224
  - spec/gnip_api/gnip/activity_spec.rb
229
225
  - spec/gnip_api/gnip/gnip_data_spec.rb
230
226
  - spec/gnip_api/gnip/message_spec.rb
231
- - spec/gnip_api/limiters/rules_spec.rb
232
227
  - spec/gnip_api/request_spec.rb
233
228
  - spec/gnip_api/response_spec.rb
234
229
  - spec/lib/test_adapter.rb
@@ -289,12 +284,12 @@ test_files:
289
284
  - spec/gnip_api/apis/power_track/rule_spec.rb
290
285
  - spec/gnip_api/apis/power_track/rules_spec.rb
291
286
  - spec/gnip_api/apis/power_track/stream_spec.rb
287
+ - spec/gnip_api/apis/search_spec.rb
292
288
  - spec/gnip_api/configuration_spec.rb
293
289
  - spec/gnip_api/endpoints_spec.rb
294
290
  - spec/gnip_api/gnip/activity_spec.rb
295
291
  - spec/gnip_api/gnip/gnip_data_spec.rb
296
292
  - spec/gnip_api/gnip/message_spec.rb
297
- - spec/gnip_api/limiters/rules_spec.rb
298
293
  - spec/gnip_api/request_spec.rb
299
294
  - spec/gnip_api/response_spec.rb
300
295
  - spec/lib/test_adapter.rb
File without changes
@@ -1,36 +0,0 @@
1
- module GnipApi
2
- module Apis
3
- module Search
4
- class Query
5
- attr_accessor :rules, :from_date, :to_date, :max_results, :next, :publisher
6
-
7
- def initialize params={}
8
- @rules = params[:rules]
9
- @from_date = params[:from_date]
10
- @to_date = params[:to_date]
11
- @max_results = params[:max_results]
12
- @next = params[:next]
13
- @publisher = params[:publisher]
14
- end
15
-
16
- def to_json
17
- hash = {}
18
- hash['query'] = @rules
19
- hash['publisher'] = @publisher
20
- hash['fromDate'] = @from_date.to_time.utc.strftime('%Y%m%d%H%M') if @from_date
21
- hash['toDate'] = @to_date.to_time.utc.strftime('%Y%m%d%H%M') if @to_date
22
- hash['next'] = @next if @next
23
- hash['maxResults'] = @max_results if @max_results
24
- hash.to_json
25
- end
26
-
27
- def valid?
28
- end
29
-
30
- private
31
- def validate
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,17 +0,0 @@
1
- module GnipApi
2
- module Apis
3
- module Search
4
- class Result
5
- attr_reader :activities, :response
6
-
7
- def initialize response
8
- @response = response
9
- end
10
-
11
- def activities
12
- @activities ||= response['results'].map { |activity| Activity.new(activity) }
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,26 +0,0 @@
1
- module GnipApi
2
- module Apis
3
- module Search
4
- class Stream
5
- attr_accessor :query, :label
6
-
7
- def initialize options={}
8
- @query = options[:query]
9
- @label = options[:label]
10
- @adapter = GnipApi::Adapter.new
11
- end
12
-
13
- def perform
14
- response = @adapter.post search_url, @query.to_json
15
- Result.new response
16
- end
17
-
18
- private
19
-
20
- def search_url
21
- GnipApi::Endpoints.search_stream(@label)
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,56 +0,0 @@
1
- module GnipApi
2
- module Limiters
3
- module Rules
4
-
5
- def rules_init
6
- @rules_last_reset = Time.now
7
- @rules_requests = 0
8
- end
9
-
10
- def rules_request_allowed?
11
- mutex.synchronize do
12
- reset_rules_if_expired!
13
- add_rules_request!
14
- return true if @rules_requests <= rules_max_requests
15
- return false
16
- end
17
- end
18
-
19
- def reset_rules_if_expired!
20
- if seconds_since_last_rules_request >= rules_expire
21
- reset_rules!
22
- end
23
- end
24
-
25
- def seconds_since_last_rules_request
26
- Time.now.to_i - @rules_last_reset.to_i
27
- end
28
-
29
- def add_rules_request!
30
- @rules_requests += 1
31
- end
32
-
33
- def reset_rules!
34
- @rules_last_reset = Time.now
35
- @rules_requests = 0
36
- end
37
-
38
- def rules_last_reset
39
- @rules_last_reset
40
- end
41
-
42
- def rules_requests
43
- @rules_requests
44
- end
45
-
46
- def rules_max_requests
47
- 5
48
- end
49
-
50
- def rules_expire
51
- 1
52
- end
53
-
54
- end
55
- end
56
- end
@@ -1,14 +0,0 @@
1
- module GnipApi
2
- class RateLimiter
3
- include GnipApi::Limiters::Rules
4
-
5
- def initialize
6
- self.rules_init
7
- end
8
-
9
- private
10
- def mutex
11
- GnipApi.config.mutex
12
- end
13
- end
14
- end
@@ -1,74 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe GnipApi::Limiters::Rules do
4
- before do
5
- @limiter = Object.new
6
- @limiter.extend(GnipApi::Limiters::Rules)
7
- @limiter.rules_init
8
- allow(@limiter).to receive(:mutex).and_return(Mutex.new)
9
- end
10
-
11
- describe '#rules_request_allowed?' do
12
- before do
13
- Timecop.freeze(Time.now)
14
- end
15
-
16
- after do
17
- Timecop.return
18
- end
19
-
20
- it 'allows 5 requests' do
21
- requests = []
22
- 5.times{requests << @limiter.rules_request_allowed?}
23
- expect(requests.uniq).to eq([true])
24
- end
25
-
26
- it 'does not allow more than 5 requests' do
27
- 5.times{@limiter.rules_request_allowed?}
28
- expect(@limiter.rules_request_allowed?).to eq(false)
29
- end
30
- end
31
-
32
- describe '#reset_rules_if_expired' do
33
- before do
34
- Timecop.freeze(Time.now)
35
- end
36
-
37
- after do
38
- Timecop.return
39
- end
40
-
41
- it 'does not reset if not expired' do
42
- current_time = @limiter.rules_last_reset
43
- current_count = @limiter.rules_requests
44
- @limiter.reset_rules_if_expired!
45
- expect(@limiter.rules_last_reset).to eq(current_time)
46
- expect(@limiter.rules_requests).to eq(current_count)
47
- end
48
-
49
- it 'resets if expired' do
50
- @limiter.add_rules_request!
51
- current_time = @limiter.rules_last_reset
52
- current_count = @limiter.rules_requests
53
- Timecop.travel(Time.at(Time.now.to_i + 1))
54
- @limiter.reset_rules_if_expired!
55
- expect(@limiter.rules_last_reset).not_to eq(current_time)
56
- expect(@limiter.rules_requests).not_to eq(current_count)
57
- end
58
- end
59
-
60
- describe '#seconds_since_last_rules_reset' do
61
- before do
62
- Timecop.freeze(Time.now)
63
- end
64
-
65
- after do
66
- Timecop.return
67
- end
68
-
69
- it 'returns number of seconds since last reset' do
70
- Timecop.travel(Time.at(Time.now.to_i + 1))
71
- expect(@limiter.seconds_since_last_rules_request).to eq(1)
72
- end
73
- end
74
- end