twingly-search 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4a32c03b5a124011f9486d4724a9390f74fd88f2
4
+ data.tar.gz: b7c26d1ba53842a58e40f25ae54abbe9c0dee8f7
5
+ SHA512:
6
+ metadata.gz: 5a3ffe5d6257cb17d9e32df29cac7e9014829b99d71aef1c0adef5cae4d338018dcbc378af4d5b4d299753851fac6c4b10c24e38ebea8e23a950647d8c250134
7
+ data.tar.gz: 9142bf21df1a9655f89c4df65ab3072a2bf7e3efc054cec70cb332ea7c37a83fb29d7442b77d40707e8843512d2c51fe5dfdde5b3741c8675aff8aa7fee258da
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .env
2
+ Gemfile.lock
3
+ .ruby-version
4
+ *.gem
data/.travis.yml ADDED
@@ -0,0 +1,27 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1
7
+ - 2.2
8
+ deploy:
9
+ provider: rubygems
10
+ api_key:
11
+ secure: QxMWXTQ3/T+0IQZl3pk3hmdoX8FcXTXEhH7Jn7Ub1A1D5faa8VNnfYsWAPjP6+VRgVfKEjAsHNMyZQNTvudpPPC/2kAwwzPvStyS+y7KnRkjZ9acC7sYVVel6cZ2lcl+t8iHY+19NRBFBWpq/P0eCAcR/Ew0XXaLZnig5h/1mQo=
12
+ gem: twingly-search
13
+ gemspec: twingly-search-api-ruby.gemspec
14
+ on:
15
+ tags: true
16
+ rvm: 2.2
17
+ repo: twingly/twingly-search-api-ruby
18
+ notifications:
19
+ email: false
20
+ hipchat:
21
+ on_success: never
22
+ on_failure: change
23
+ template:
24
+ - '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} (<a href="%{build_url}">Details</a>/<a href="%{compare_url}">Change view</a>)'
25
+ format: html
26
+ rooms:
27
+ secure: KU2mE9mcqvBczfiCTgTsgMmJPyW02AH/0Rzcli7oj3HVbiHGw8t5JlBQWYROF5TPht0kFhGkiwVPl6HUt/VAGxOIBsOp+/8MXR6aK5FkdIw6g8DMKlDjm9a2QijOT9rvat5bZ3l6hm3snojgkI3s9pLKmLq9l+KalAsPcevwKAQ=
data/CHANGELOG.md ADDED
@@ -0,0 +1,63 @@
1
+ # Change Log
2
+
3
+ ## [2.0.1](https://github.com/twingly/twingly-search-api-ruby/tree/2.0.1) (2015-09-24)
4
+ [Full Changelog](https://github.com/twingly/twingly-search-api-ruby/compare/2.0.0...2.0.1)
5
+
6
+ **Fixed bugs:**
7
+
8
+ - Crash when pattern is empty string [\#17](https://github.com/twingly/twingly-search-api-ruby/issues/17)
9
+
10
+ **Merged pull requests:**
11
+
12
+ - Do not allow empty search pattern [\#18](https://github.com/twingly/twingly-search-api-ruby/pull/18) ([twingly-mob](https://github.com/twingly-mob))
13
+ - Generate Changelog \(with instructions to update it\) [\#16](https://github.com/twingly/twingly-search-api-ruby/pull/16) ([jage](https://github.com/jage))
14
+
15
+ ## [2.0.0](https://github.com/twingly/twingly-search-api-ruby/tree/2.0.0) (2015-09-14)
16
+ [Full Changelog](https://github.com/twingly/twingly-search-api-ruby/compare/1.0.1...2.0.0)
17
+
18
+ **Implemented enhancements:**
19
+
20
+ - Release gem to rubygems.org [\#10](https://github.com/twingly/twingly-search-api-ruby/issues/10)
21
+
22
+ **Merged pull requests:**
23
+
24
+ - Improve time pagination \(breaking compatibility for Query\#start\_time and Query\#end\_time\) [\#15](https://github.com/twingly/twingly-search-api-ruby/pull/15) ([jage](https://github.com/jage))
25
+
26
+ ## [1.0.1](https://github.com/twingly/twingly-search-api-ruby/tree/1.0.1) (2015-04-29)
27
+ [Full Changelog](https://github.com/twingly/twingly-search-api-ruby/compare/1.0.0...1.0.1)
28
+
29
+ **Fixed bugs:**
30
+
31
+ - Support Ruby 2.2 [\#12](https://github.com/twingly/twingly-search-api-ruby/issues/12)
32
+ - HTTPS broke compatibility with Ruby 1.9.3 [\#8](https://github.com/twingly/twingly-search-api-ruby/issues/8)
33
+
34
+ **Closed issues:**
35
+
36
+ - Use the rspec-its gem [\#11](https://github.com/twingly/twingly-search-api-ruby/issues/11)
37
+
38
+ **Merged pull requests:**
39
+
40
+ - Fix deprecations [\#14](https://github.com/twingly/twingly-search-api-ruby/pull/14) ([walro](https://github.com/walro))
41
+ - Support Ruby 2.2 [\#13](https://github.com/twingly/twingly-search-api-ruby/pull/13) ([dentarg](https://github.com/dentarg))
42
+ - Use Faraday instead of Net::HTTP directly [\#9](https://github.com/twingly/twingly-search-api-ruby/pull/9) ([jage](https://github.com/jage))
43
+
44
+ ## [1.0.0](https://github.com/twingly/twingly-search-api-ruby/tree/1.0.0) (2014-10-30)
45
+ **Implemented enhancements:**
46
+
47
+ - Use HTTPS for API access [\#7](https://github.com/twingly/twingly-search-api-ruby/issues/7)
48
+ - Remove swedish comment [\#5](https://github.com/twingly/twingly-search-api-ruby/issues/5)
49
+ - Rewrite history to remove huge vcr-cassettes [\#4](https://github.com/twingly/twingly-search-api-ruby/issues/4)
50
+ - Remove humongous vcr cassettes [\#1](https://github.com/twingly/twingly-search-api-ruby/issues/1)
51
+
52
+ **Closed issues:**
53
+
54
+ - Add a LICENSE [\#6](https://github.com/twingly/twingly-search-api-ruby/issues/6)
55
+ - Wrap lines at 72 characters [\#2](https://github.com/twingly/twingly-search-api-ruby/issues/2)
56
+
57
+ **Merged pull requests:**
58
+
59
+ - Refactor to improve readability [\#3](https://github.com/twingly/twingly-search-api-ruby/pull/3) ([jage](https://github.com/jage))
60
+
61
+
62
+
63
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Twingly AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Twingly Search API Ruby
2
+
3
+ [![Build Status](https://travis-ci.org/twingly/twingly-analytics-api-ruby.png?branch=master)](https://travis-ci.org/twingly/twingly-analytics-api-ruby)
4
+ [![Code Climate](https://codeclimate.com/github/twingly/twingly-analytics-api-ruby.png)](https://codeclimate.com/github/twingly/twingly-analytics-api-ruby)
5
+
6
+ A Ruby gem for Twingly's Search API (previously known as Analytics API). Twingly is a blog search service that provides a searchable API known as [Twingly Search API](https://developer.twingly.com/resources/search/).
7
+
8
+ ## Installation
9
+
10
+ Install via RubyGems
11
+
12
+ ```Shell
13
+ gem install twingly-search
14
+ ```
15
+
16
+ Or add to your application's [Gemfile](http://bundler.io/gemfile.html) and then run `bundle`
17
+
18
+ ```Ruby
19
+ gem 'twingly-search'
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```Ruby
25
+ require 'twingly/search'
26
+
27
+ client = Twingly::Search::Client.new
28
+ query = client.query
29
+ query.pattern = 'github page-size:10'
30
+ query.language = 'sv'
31
+ result = query.execute
32
+ => #<Twingly::Search::Result:0x3ff7adcbe3d4 @posts, @number_of_matches_returned=10, @number_of_matches_total=3035221>
33
+ result.posts # will include all returned posts
34
+ ```
35
+
36
+ The `twingly-search` gem talks to a commercial blog search API and requires an API key. Best practice is to set the `TWINGLY_SEARCH_KEY` environment variable to the obtained key. `Twingly::Search::Client` can be passed a key at initialization if your setup does not allow environment variables.
37
+
38
+ Example code can be found in [examples/](examples/).
39
+
40
+ Too learn more about the capabilities of this API you should read the [Twingly Search API documentation](https://developer.twingly.com/resources/search/).
41
+
42
+ ## Requirements
43
+
44
+ * API key, contact sales@twingly.com to get one
45
+ * Ruby 1.9, 2.0, 2.1, 2.2
46
+
47
+ ## Development and release
48
+
49
+ 1. Make sure the master branch has an up-to-date changelog. Generate with `rake changelog`. Set `CHANGELOG_GITHUB_TOKEN` to a personal access token to increase the API rate limit. (The changelog uses [GitHub Changelog Generator](https://github.com/skywinder/github-changelog-generator/))
50
+ 1. Bump version in `lib/twingly/search/version.rb`, follow [Semantic Versioning 2.0.0](http://semver.org/)
51
+ 1. Build and release gem with `bundle exec rake release`. This will create a git tag for the version and push the `.gem` file to https://rubygems.org/.
52
+ 1. Update release information on the [releases page].
53
+
54
+ [releases page]: https://github.com/twingly/twingly-search-api-ruby/releases
55
+
56
+ ## License
57
+
58
+ The MIT License (MIT)
59
+
60
+ Copyright (c) 2013 Twingly AB
61
+
62
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
63
+ this software and associated documentation files (the "Software"), to deal in
64
+ the Software without restriction, including without limitation the rights to
65
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
66
+ the Software, and to permit persons to whom the Software is furnished to do so,
67
+ subject to the following conditions:
68
+
69
+ The above copyright notice and this permission notice shall be included in all
70
+ copies or substantial portions of the Software.
71
+
72
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
74
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
75
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
76
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
77
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require "rake"
2
+ require "bundler/setup"
3
+ require "bundler/gem_tasks"
4
+
5
+ desc "Run specs"
6
+ task :spec do
7
+ require "rspec/core/rake_task"
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.rspec_opts = %w(-fd -c)
10
+ end
11
+ end
12
+
13
+ require "github_changelog_generator/task"
14
+ GitHubChangelogGenerator::RakeTask.new(:changelog) do |config|
15
+ config.user = "twingly"
16
+ config.project = "twingly-search-api-ruby"
17
+ end
18
+
19
+ desc "Synonym for spec"
20
+ task :test => :spec
21
+ desc "Synonym for spec"
22
+ task :tests => :spec
23
+ task :default => :spec
data/examples/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'twingly-search', path: '../'
@@ -0,0 +1,29 @@
1
+ Bundler.require
2
+
3
+ class SearchPostStream
4
+ def initialize(keyword, language: nil)
5
+ # Set environment variable TWINGLY_SEARCH_KEY
6
+ client = Twingly::Search::Client.new
7
+ @query = client.query
8
+ @query.language = language
9
+ @query.pattern = "sort-order:asc sort:published #{keyword}"
10
+ end
11
+
12
+ def each
13
+ loop do
14
+ result = @query.execute
15
+ result.posts.each do |post|
16
+ yield post
17
+ end
18
+
19
+ break if result.all_results_returned?
20
+
21
+ @query.start_time = result.posts.last.published
22
+ end
23
+ end
24
+ end
25
+
26
+ stream = SearchPostStream.new("(github) AND (hipchat OR slack)")
27
+ stream.each do |post|
28
+ puts post.url
29
+ end
@@ -0,0 +1,11 @@
1
+ Bundler.require
2
+
3
+ # Set environment variable TWINGLY_SEARCH_KEY
4
+ client = Twingly::Search::Client.new
5
+ query = client.query
6
+ query.pattern = '"hello world"'
7
+ query.start_time = Time.now - (24 * 3600) # search last day
8
+ result = query.execute
9
+ result.posts.each do |post|
10
+ puts post.url
11
+ end
@@ -0,0 +1,6 @@
1
+ require 'twingly/search/client'
2
+ require 'twingly/search/query'
3
+ require 'twingly/search/result'
4
+ require 'twingly/search/parser'
5
+ require 'twingly/search/post'
6
+ require 'twingly/search/version'
@@ -0,0 +1,19 @@
1
+ module Twingly
2
+ module Search
3
+ class Client
4
+ attr_accessor :api_key
5
+
6
+ def initialize(api_key = nil)
7
+ @api_key = api_key || env_api_key || fail("Missing API key")
8
+ end
9
+
10
+ def query
11
+ Query.new(self)
12
+ end
13
+ private
14
+ def env_api_key
15
+ ENV['TWINGLY_SEARCH_KEY']
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ require 'nokogiri'
2
+
3
+ module Twingly
4
+ module Search
5
+ class Parser
6
+ def parse(document)
7
+ result = Result.new
8
+ nokogiri = Nokogiri::XML(document)
9
+
10
+ failure = nokogiri.at_xpath('//name:blogstream/name:operationResult[@resultType="failure"]', :name => 'http://www.twingly.com')
11
+ fail failure.text if failure
12
+
13
+ result.number_of_matches_returned = nokogiri.at_xpath('/twinglydata/@numberOfMatchesReturned').value.to_i
14
+ result.number_of_matches_total = nokogiri.at_xpath('/twinglydata/@numberOfMatchesTotal').value.to_i
15
+ result.seconds_elapsed = nokogiri.at_xpath('/twinglydata/@secondsElapsed').value.to_f
16
+
17
+ nokogiri.xpath('//post').each do |post|
18
+ result.posts << parse_post(post)
19
+ end
20
+
21
+ result
22
+ end
23
+ private
24
+ def parse_post(element)
25
+ post_params = {}
26
+ element.element_children.each do |child|
27
+ if child.name == 'tags'
28
+ post_params[child.name] = parse_tags(child) if child.name == 'tags'
29
+ else
30
+ post_params[child.name] = child.text
31
+ end
32
+ end
33
+ post = Post.new
34
+ post.set_values(post_params)
35
+ post
36
+ end
37
+
38
+ def parse_tags(element)
39
+ element.element_children.map do |child|
40
+ child.text
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ require 'date'
4
+
5
+ module Twingly
6
+ module Search
7
+ class Post
8
+ attr_reader :url, :title, :summary, :language_code, :indexed,
9
+ :published, :blog_url, :blog_name, :authority, :blog_rank, :tags
10
+
11
+ def set_values(params)
12
+ @url = params.fetch('url')
13
+ @title = params.fetch('title')
14
+ @summary = params.fetch('summary')
15
+ @language_code = params.fetch('languageCode')
16
+ @published = DateTime.parse(params.fetch('published'))
17
+ @indexed = DateTime.parse(params.fetch('indexed'))
18
+ @blog_url = params.fetch('blogUrl')
19
+ @blog_name = params.fetch('blogName')
20
+ @authority = params.fetch('authority').to_i
21
+ @blog_rank = params.fetch('blogRank').to_i
22
+ @tags = params.fetch('tags', [])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ require 'faraday'
2
+
3
+ module Twingly
4
+ module Search
5
+ class Query
6
+ attr_accessor :pattern, :language, :client, :start_time, :end_time
7
+
8
+ BASE_URL = 'https://api.twingly.com'
9
+ SEARCH_PATH = '/analytics/Analytics.ashx'
10
+
11
+ def initialize(client)
12
+ @client = client
13
+ end
14
+
15
+ def url
16
+ "#{BASE_URL}#{SEARCH_PATH}?#{url_parameters}"
17
+ end
18
+
19
+ def execute
20
+ Parser.new.parse(get_response.body)
21
+ end
22
+
23
+ def url_parameters
24
+ Faraday::Utils.build_query(request_parameters)
25
+ end
26
+
27
+ def request_parameters
28
+ fail("Missing pattern") if pattern.to_s.empty?
29
+
30
+ {
31
+ :key => client.api_key,
32
+ :searchpattern => pattern,
33
+ :documentlang => language,
34
+ :ts => ts,
35
+ :tsTo => ts_to,
36
+ :xmloutputversion => 2
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ def ts
43
+ start_time.to_time.strftime("%F %T") if start_time
44
+ end
45
+
46
+ def ts_to
47
+ end_time.to_time.strftime("%F %T") if end_time
48
+ end
49
+
50
+ def get_response
51
+ connection = Faraday.new(:url => BASE_URL) do |faraday|
52
+ faraday.request :url_encoded
53
+ faraday.adapter Faraday.default_adapter
54
+ end
55
+ connection.headers[:user_agent] = "Twingly Search Ruby Client/#{VERSION}"
56
+ connection.get(SEARCH_PATH, request_parameters)
57
+ end
58
+ end
59
+ end
60
+ end