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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +102 -12
- data/lib/gnip_api/apis/power_track/rules.rb +2 -8
- data/lib/gnip_api/apis/power_track/stream.rb +2 -2
- data/lib/gnip_api/apis/search.rb +69 -0
- data/lib/gnip_api/configuration.rb +1 -4
- data/lib/gnip_api/endpoints.rb +4 -4
- data/lib/gnip_api/errors.rb +8 -0
- data/lib/gnip_api/version.rb +1 -1
- data/lib/gnip_api.rb +1 -10
- data/spec/gnip_api/apis/search_spec.rb +29 -0
- data/spec/gnip_api/configuration_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- metadata +5 -10
- data/lib/gnip_api/apis/search/count.rb +0 -0
- data/lib/gnip_api/apis/search/query.rb +0 -36
- data/lib/gnip_api/apis/search/result.rb +0 -17
- data/lib/gnip_api/apis/search/stream.rb +0 -26
- data/lib/gnip_api/limiters/rules.rb +0 -56
- data/lib/gnip_api/rate_limiter.rb +0 -14
- data/spec/gnip_api/limiters/rules_spec.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a0f89ada9f7ec8c66ff45982702e37a0649e8ff
|
4
|
+
data.tar.gz: 65a52d03b722a14f6264c8d51086d3df9e24cdf9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1560448fb7366e1422971587abb31fbfe16c121faaf28d37f7cdfcd7aa81019b05d789e053c4ce3be7f20bd67e23d15bc9d46bde9cd9e0ddd226b5f2805f887f
|
7
|
+
data.tar.gz: c4750dbfcae74f230df1b4a93099b1786715ce5a92fb1b60ad844ba221d7ec75549d37d43e5cf7f113f7e25db8e7a2fe7eb9e54d484b965011038f9dda1090b1
|
data/Gemfile.lock
CHANGED
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
|
-
-
|
8
|
-
-
|
9
|
-
-
|
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.
|
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
|
-
###
|
58
|
+
### Search API
|
48
59
|
|
49
|
-
|
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
|
-
|
63
|
+
```ruby
|
64
|
+
rule = GnipApi::Apis::PowerTrack::Rule.new :value => 'keyword1 OR keyword2'
|
65
|
+
end
|
66
|
+
```
|
52
67
|
|
53
|
-
|
68
|
+
Then you can query the search endpoint. *Only counts are available currently*.
|
54
69
|
|
55
|
-
|
70
|
+
```ruby
|
71
|
+
results = GnipApi::Apis::Search.new.counts :rule => rule
|
72
|
+
end
|
73
|
+
```
|
56
74
|
|
57
|
-
|
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
|
-
|
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
|
@@ -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, :
|
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
|
data/lib/gnip_api/endpoints.rb
CHANGED
@@ -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
|
13
|
-
URI("https://
|
12
|
+
def search_activities label
|
13
|
+
URI("https://gnip-api.twitter.com/search/fullarchive/accounts/#{account}/#{label}")
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
URI("https://
|
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
|
data/lib/gnip_api/errors.rb
CHANGED
@@ -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'
|
data/lib/gnip_api/version.rb
CHANGED
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
|
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
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
|
+
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-
|
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
|
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,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
|