twingly-search 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -15
- data/CHANGELOG.md +7 -0
- data/README.md +13 -4
- data/examples/find_all_posts_mentioning_github.rb +8 -2
- data/lib/twingly/livefeed.rb +2 -0
- data/lib/twingly/livefeed/client.rb +5 -3
- data/lib/twingly/livefeed/error.rb +6 -1
- data/lib/twingly/livefeed/parser.rb +6 -3
- data/lib/twingly/livefeed/post.rb +8 -4
- data/lib/twingly/livefeed/result.rb +13 -9
- data/lib/twingly/livefeed/version.rb +3 -1
- data/lib/twingly/search.rb +2 -0
- data/lib/twingly/search/client.rb +4 -2
- data/lib/twingly/search/error.rb +12 -2
- data/lib/twingly/search/parser.rb +6 -3
- data/lib/twingly/search/post.rb +8 -4
- data/lib/twingly/search/query.rb +9 -2
- data/lib/twingly/search/result.rb +11 -5
- data/lib/twingly/search/version.rb +3 -1
- data/profiler/fixtures/vcr_cassettes/blog_livefeed_100.yml +43 -0
- data/profiler/fixtures/vcr_cassettes/blog_search_100.yml +43 -0
- data/profiler/profile_helper.rb +18 -0
- data/profiler/profile_livefeed.rb +21 -0
- data/profiler/profile_search.rb +23 -0
- data/spec/client_spec.rb +3 -3
- data/spec/error_spec.rb +4 -0
- data/spec/fixtures/unauthenticated_api_key_result.xml +3 -0
- data/spec/fixtures/unauthorized_api_key_result.xml +3 -3
- data/spec/livefeed/client_spec.rb +2 -2
- data/spec/livefeed/error_spec.rb +1 -0
- data/spec/livefeed/parser_spec.rb +3 -3
- data/spec/livefeed/result_spec.rb +22 -8
- data/spec/parser_spec.rb +11 -3
- data/spec/result_spec.rb +20 -6
- data/twingly-search-api-ruby.gemspec +3 -1
- metadata +39 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 816d2bcb38d40a6f83dd9c815f3eded749735d06c16e66910c9d19eccda14a56
|
4
|
+
data.tar.gz: 3d70d46edfa3c201e06fc36292498a3669ad63c9bbf0a6b509b758efa2d23138
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf6d1617263939de594f571031ee98fb0ed592838e0d53a5a221850511f7e948992af2e59c3630c8311fec0f53cf6d29f9a1a3594bc17d324817b6c284acd56c
|
7
|
+
data.tar.gz: 67c9e8cd2b7180fbe34401b16cab2d6a0f79ed5764d356843bce1b520f7473e787a8d3d47dcb88a34b94c7c2e92ce2af285974e82c5558e6d734ee80132b6f94
|
data/.travis.yml
CHANGED
@@ -4,20 +4,9 @@ before_install:
|
|
4
4
|
- gem update bundler
|
5
5
|
cache: bundler
|
6
6
|
rvm:
|
7
|
-
- 2.
|
8
|
-
- 2.
|
9
|
-
- 2.
|
10
|
-
- 2.
|
11
|
-
- 2.5.0
|
12
|
-
- jruby-9.0.5.0
|
13
|
-
- jruby-9.1.15.0
|
7
|
+
- 2.4.6
|
8
|
+
- 2.5.5
|
9
|
+
- 2.6.2
|
10
|
+
- jruby-9.2.6.0
|
14
11
|
notifications:
|
15
12
|
email: false
|
16
|
-
hipchat:
|
17
|
-
on_success: never
|
18
|
-
on_failure: change
|
19
|
-
template:
|
20
|
-
- '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} (<a href="%{build_url}">Details</a>/<a href="%{compare_url}">Change view</a>)'
|
21
|
-
format: html
|
22
|
-
rooms:
|
23
|
-
secure: KU2mE9mcqvBczfiCTgTsgMmJPyW02AH/0Rzcli7oj3HVbiHGw8t5JlBQWYROF5TPht0kFhGkiwVPl6HUt/VAGxOIBsOp+/8MXR6aK5FkdIw6g8DMKlDjm9a2QijOT9rvat5bZ3l6hm3snojgkI3s9pLKmLq9l+KalAsPcevwKAQ=
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v5.2.0](https://github.com/twingly/twingly-search-api-ruby/tree/v5.2.0) (2018-05-17)
|
4
|
+
[Full Changelog](https://github.com/twingly/twingly-search-api-ruby/compare/v5.1.4...v5.2.0)
|
5
|
+
|
6
|
+
**Merged pull requests:**
|
7
|
+
|
8
|
+
- Add Post\#to\_h for both LiveFeed and Search [\#77](https://github.com/twingly/twingly-search-api-ruby/pull/77) ([dentarg](https://github.com/dentarg))
|
9
|
+
|
3
10
|
## [v5.1.4](https://github.com/twingly/twingly-search-api-ruby/tree/v5.1.4) (2018-02-23)
|
4
11
|
[Full Changelog](https://github.com/twingly/twingly-search-api-ruby/compare/v5.1.3...v5.1.4)
|
5
12
|
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ query = client.query do |query|
|
|
46
46
|
end
|
47
47
|
|
48
48
|
result = query.execute
|
49
|
-
=> #<Twingly::Search::Result:
|
49
|
+
=> #<Twingly::Search::Result:0x3fca8ad3aa60 posts, number_of_matches_returned=10, number_of_matches_total=281, incomplete_result=false, seconds_elapsed=0.239, all_results_returned?=false, incomplete?=false>
|
50
50
|
result.posts # will include all returned posts
|
51
51
|
```
|
52
52
|
|
@@ -64,7 +64,7 @@ end
|
|
64
64
|
|
65
65
|
# get the next chunk of posts
|
66
66
|
result = client.next_result
|
67
|
-
=> #<Twingly::LiveFeed::Result:
|
67
|
+
=> #<Twingly::LiveFeed::Result:0x3fca8ad4e81c posts, ts=2019-03-27 12:52:54 UTC, from=2019-03-27 11:52:53 UTC, number_of_posts=709, max_number_of_posts=1000, first_post=2019-03-27 11:53:02 UTC, last_post=2019-03-27 12:52:42 UTC, next_timestamp=2019-03-27 12:52:42 UTC>
|
68
68
|
|
69
69
|
result.posts # will include all returned posts
|
70
70
|
```
|
@@ -73,8 +73,8 @@ result.posts # will include all returned posts
|
|
73
73
|
|
74
74
|
* API key, [sign up](https://www.twingly.com/try-for-free) via [twingly.com](https://www.twingly.com/) to get one
|
75
75
|
* Ruby
|
76
|
-
* Ruby
|
77
|
-
* JRuby
|
76
|
+
* Ruby >= 2.4
|
77
|
+
* JRuby >= 9.2
|
78
78
|
|
79
79
|
## Development
|
80
80
|
|
@@ -88,6 +88,15 @@ Run the tests
|
|
88
88
|
|
89
89
|
bundle exec rake
|
90
90
|
|
91
|
+
### Profiling
|
92
|
+
|
93
|
+
It's possible to profile memory and object allocation:
|
94
|
+
|
95
|
+
bundle exec ruby profiler/profile_livefeed.rb
|
96
|
+
bundle exec ruby profiler/profile_search.rb
|
97
|
+
|
98
|
+
Currently using [memory_profiler](https://github.com/SamSaffron/memory_profiler) for reports and [VCR](https://github.com/vcr/vcr) for saving requests (to make runs comparable).
|
99
|
+
|
91
100
|
### Release
|
92
101
|
|
93
102
|
1. Make a commit bumping the version in `lib/twingly/search/version.rb`, follow [Semantic Versioning 2.0.0](http://semver.org/). No need to push as this will be taken care of automatically in the next step.
|
@@ -8,8 +8,14 @@ class SearchPostStream
|
|
8
8
|
end
|
9
9
|
|
10
10
|
@query = client.query do |query|
|
11
|
-
|
12
|
-
|
11
|
+
query_parts = [
|
12
|
+
"sort-order:asc",
|
13
|
+
"sort:published",
|
14
|
+
keyword,
|
15
|
+
]
|
16
|
+
query_parts << "lang:#{language}" if language
|
17
|
+
|
18
|
+
query.search_query = query_parts.join(" ")
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
data/lib/twingly/livefeed.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "faraday"
|
2
4
|
require "time"
|
3
5
|
|
@@ -30,7 +32,7 @@ module Twingly
|
|
30
32
|
# @option options [String] :max_posts the maximum number of posts that can
|
31
33
|
# be returned for each request
|
32
34
|
# @option options [String] :timestamp the timestamp to start the client at
|
33
|
-
# @raise [
|
35
|
+
# @raise [AuthenticationError] if an API key is not set
|
34
36
|
def initialize(api_key = nil, options = {})
|
35
37
|
@api_key = api_key
|
36
38
|
@user_agent = options.fetch(:user_agent) { DEFAULT_USER_AGENT }
|
@@ -49,7 +51,7 @@ module Twingly
|
|
49
51
|
# then returns the result.
|
50
52
|
#
|
51
53
|
# @raise [QueryError] if the timestamp is invalid.
|
52
|
-
# @raise [
|
54
|
+
# @raise [AuthenticationError] if the API couldn't authenticate you. Make sure your API key is correct.
|
53
55
|
# @raise [ServerError] if the query could not be executed due to a server error.
|
54
56
|
# @return [Result] the result for this request.
|
55
57
|
def next_result
|
@@ -110,7 +112,7 @@ module Twingly
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def api_key_missing
|
113
|
-
fail
|
115
|
+
fail AuthenticationError, "No API key has been provided."
|
114
116
|
end
|
115
117
|
|
116
118
|
def assert_valid_time(time)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Twingly
|
2
4
|
module LiveFeed
|
3
5
|
class Error < StandardError
|
@@ -7,7 +9,7 @@ module Twingly
|
|
7
9
|
when /^400/, /^404/
|
8
10
|
QueryError
|
9
11
|
when /^401/
|
10
|
-
|
12
|
+
AuthenticationError
|
11
13
|
else
|
12
14
|
ServerError
|
13
15
|
end
|
@@ -19,6 +21,9 @@ module Twingly
|
|
19
21
|
class AuthError < Error
|
20
22
|
end
|
21
23
|
|
24
|
+
class AuthenticationError < AuthError
|
25
|
+
end
|
26
|
+
|
22
27
|
class ServerError < Error
|
23
28
|
end
|
24
29
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'nokogiri'
|
2
4
|
|
3
5
|
module Twingly
|
@@ -45,9 +47,10 @@ module Twingly
|
|
45
47
|
def parse_post(element)
|
46
48
|
post_params = {}
|
47
49
|
element.element_children.each do |child|
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
name = child.name.freeze
|
51
|
+
post_params[name] =
|
52
|
+
case name
|
53
|
+
when "tags", "links", "images"
|
51
54
|
parse_array(child)
|
52
55
|
when "coordinates"
|
53
56
|
parse_coordinates(child)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Twingly
|
4
5
|
module LiveFeed
|
@@ -36,6 +37,9 @@ module Twingly
|
|
36
37
|
:published_at, :reindexed_at, :inlinks_count, :blog_id, :blog_name,
|
37
38
|
:blog_url, :blog_rank, :authority
|
38
39
|
|
40
|
+
EMPTY_ARRAY = [].freeze
|
41
|
+
EMPTY_HASH = {}.freeze
|
42
|
+
|
39
43
|
# Sets all instance variables for the {Post}, given a Hash.
|
40
44
|
#
|
41
45
|
# @param [Hash] params containing blog post data.
|
@@ -47,10 +51,10 @@ module Twingly
|
|
47
51
|
@text = params.fetch('text')
|
48
52
|
@language_code = params.fetch('languageCode')
|
49
53
|
@location_code = params.fetch('locationCode')
|
50
|
-
@coordinates = params.fetch('coordinates'
|
51
|
-
@links = params.fetch('links'
|
52
|
-
@tags = params.fetch('tags'
|
53
|
-
@images = params.fetch('images'
|
54
|
+
@coordinates = params.fetch('coordinates') { EMPTY_HASH }
|
55
|
+
@links = params.fetch('links') { EMPTY_ARRAY }
|
56
|
+
@tags = params.fetch('tags') { EMPTY_ARRAY }
|
57
|
+
@images = params.fetch('images') { EMPTY_ARRAY }
|
54
58
|
@indexed_at = Time.parse(params.fetch('indexedAt'))
|
55
59
|
@published_at = Time.parse(params.fetch('publishedAt'))
|
56
60
|
@reindexed_at = Time.parse(params.fetch('reindexedAt'))
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Twingly
|
2
4
|
module LiveFeed
|
3
5
|
# Represents a result from a request to the LiveFeed API
|
@@ -23,16 +25,18 @@ module Twingly
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def inspect
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
instance_methods = [
|
29
|
+
"posts",
|
30
|
+
"ts=#{self.ts}",
|
31
|
+
"from=#{self.from}",
|
32
|
+
"number_of_posts=#{self.number_of_posts}",
|
33
|
+
"max_number_of_posts=#{self.max_number_of_posts}",
|
34
|
+
"first_post=#{self.first_post}",
|
35
|
+
"last_post=#{self.last_post}",
|
36
|
+
"next_timestamp=#{self.next_timestamp}",
|
37
|
+
].join(", ")
|
34
38
|
|
35
|
-
sprintf("#<%s:0x%x %s>", self.class.name, __id__,
|
39
|
+
sprintf("#<%s:0x%x %s>", self.class.name, __id__, instance_methods)
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
data/lib/twingly/search.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "faraday"
|
2
4
|
|
3
5
|
module Twingly
|
@@ -19,7 +21,7 @@ module Twingly
|
|
19
21
|
# @param options [Hash]
|
20
22
|
# @option options [String] :user_agent the user agent to be used
|
21
23
|
# for all requests
|
22
|
-
# @raise [
|
24
|
+
# @raise [AuthenticationError] if an API key is not set.
|
23
25
|
def initialize(api_key = nil, options = {})
|
24
26
|
@api_key = api_key
|
25
27
|
@user_agent = options.fetch(:user_agent) { DEFAULT_USER_AGENT }
|
@@ -70,7 +72,7 @@ module Twingly
|
|
70
72
|
end
|
71
73
|
|
72
74
|
def api_key_missing
|
73
|
-
fail
|
75
|
+
fail AuthenticationError, "No API key has been provided."
|
74
76
|
end
|
75
77
|
end
|
76
78
|
end
|
data/lib/twingly/search/error.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Twingly
|
2
4
|
module Search
|
3
5
|
class Error < StandardError
|
@@ -6,8 +8,10 @@ module Twingly
|
|
6
8
|
case code.to_s
|
7
9
|
when /^400/, /^404/
|
8
10
|
QueryError
|
9
|
-
when /^401
|
10
|
-
|
11
|
+
when /^401/ # E.g. API key not enabled
|
12
|
+
AuthenticationError
|
13
|
+
when /^402/ # E.g. language access denied
|
14
|
+
AuthorizationError
|
11
15
|
else
|
12
16
|
ServerError
|
13
17
|
end
|
@@ -19,6 +23,12 @@ module Twingly
|
|
19
23
|
class AuthError < Error
|
20
24
|
end
|
21
25
|
|
26
|
+
class AuthenticationError < AuthError
|
27
|
+
end
|
28
|
+
|
29
|
+
class AuthorizationError < AuthError
|
30
|
+
end
|
31
|
+
|
22
32
|
class ServerError < Error
|
23
33
|
end
|
24
34
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'nokogiri'
|
2
4
|
|
3
5
|
module Twingly
|
@@ -43,9 +45,10 @@ module Twingly
|
|
43
45
|
def parse_post(element)
|
44
46
|
post_params = {}
|
45
47
|
element.element_children.each do |child|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
name = child.name.freeze
|
49
|
+
post_params[name] =
|
50
|
+
case name
|
51
|
+
when "tags", "links", "images"
|
49
52
|
parse_array(child)
|
50
53
|
when "coordinates"
|
51
54
|
parse_coordinates(child)
|
data/lib/twingly/search/post.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Twingly
|
4
5
|
module Search
|
@@ -35,6 +36,9 @@ module Twingly
|
|
35
36
|
:published_at, :reindexed_at, :inlinks_count, :blog_id, :blog_name,
|
36
37
|
:blog_url, :blog_rank, :authority
|
37
38
|
|
39
|
+
EMPTY_ARRAY = [].freeze
|
40
|
+
EMPTY_HASH = {}.freeze
|
41
|
+
|
38
42
|
# Sets all instance variables for the {Post}, given a Hash.
|
39
43
|
#
|
40
44
|
# @param [Hash] params containing blog post data.
|
@@ -46,10 +50,10 @@ module Twingly
|
|
46
50
|
@text = params.fetch('text')
|
47
51
|
@language_code = params.fetch('languageCode')
|
48
52
|
@location_code = params.fetch('locationCode')
|
49
|
-
@coordinates = params.fetch('coordinates'
|
50
|
-
@links = params.fetch('links'
|
51
|
-
@tags = params.fetch('tags'
|
52
|
-
@images = params.fetch('images'
|
53
|
+
@coordinates = params.fetch('coordinates') { EMPTY_HASH }
|
54
|
+
@links = params.fetch('links') { EMPTY_ARRAY }
|
55
|
+
@tags = params.fetch('tags') { EMPTY_ARRAY }
|
56
|
+
@images = params.fetch('images') { EMPTY_ARRAY }
|
53
57
|
@indexed_at = Time.parse(params.fetch('indexedAt'))
|
54
58
|
@published_at = Time.parse(params.fetch('publishedAt'))
|
55
59
|
@reindexed_at = Time.parse(params.fetch('reindexedAt'))
|
data/lib/twingly/search/query.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "faraday"
|
2
4
|
require "time"
|
3
5
|
|
@@ -48,7 +50,11 @@ module Twingly
|
|
48
50
|
#
|
49
51
|
# @param client [Client] the client that this query should be connected to.
|
50
52
|
def initialize(client)
|
51
|
-
@client
|
53
|
+
@client = client
|
54
|
+
@start_time = nil
|
55
|
+
@end_time = nil
|
56
|
+
@language = nil
|
57
|
+
|
52
58
|
yield self if block_given?
|
53
59
|
end
|
54
60
|
|
@@ -60,7 +66,8 @@ module Twingly
|
|
60
66
|
# Executes the query and returns the result.
|
61
67
|
#
|
62
68
|
# @raise [QueryError] if {#search_query} is empty.
|
63
|
-
# @raise [
|
69
|
+
# @raise [AuthenticationError] if the API couldn't authenticate you. Make sure your API key is correct.
|
70
|
+
# @raise [AuthorizationError] if you don't have access to something.
|
64
71
|
# @raise [ServerError] if the query could not be executed due to a server error.
|
65
72
|
# @return [Result] the result for this query.
|
66
73
|
def execute
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Twingly
|
2
4
|
module Search
|
3
5
|
# Represents a result from a {Query} to the Search API
|
@@ -35,12 +37,16 @@ module Twingly
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def inspect
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
instance_methods = [
|
41
|
+
"posts",
|
42
|
+
"number_of_matches_returned=#{self.number_of_matches_returned}",
|
43
|
+
"number_of_matches_total=#{self.number_of_matches_total}",
|
44
|
+
"seconds_elapsed=#{self.seconds_elapsed}",
|
45
|
+
"all_results_returned?=#{self.all_results_returned?}",
|
46
|
+
"incomplete?=#{self.incomplete?}",
|
47
|
+
].join(", ")
|
42
48
|
|
43
|
-
sprintf("#<%s:0x%x %s>", self.class.name, __id__,
|
49
|
+
sprintf("#<%s:0x%x %s>", self.class.name, __id__, instance_methods)
|
44
50
|
end
|
45
51
|
end
|
46
52
|
end
|