polipus-elasticsearch 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ Gemfile.lock
31
+ # .ruby-version
32
+ # .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Stefano Fontanelli
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Polipus: addons for ElasticSearch
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'polipus-elasticsearch'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install polipus-elasticsearch
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/polipus-elasticsearch/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ # coding: utf-8
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,168 @@
1
+ require 'elasticsearch/model'
2
+
3
+ ENV['POLIPUS_ELASTICSEACH_INDEX_SHARDS'] ||= '1'
4
+ ENV['POLIPUS_ELASTICSEACH_INDEX_REPLICAS'] ||= '0'
5
+
6
+ module Polipus
7
+ module ElasticSearch
8
+ class Page
9
+ include Elasticsearch::Model
10
+
11
+ DEFAULT_INDEX_NAME = 'polipus-pages'
12
+ document_type 'polipus_page'
13
+ index_name DEFAULT_INDEX_NAME
14
+
15
+ settings(
16
+ index: {
17
+ number_of_shards: ENV['POLIPUS_ELASTICSEACH_INDEX_SHARDS'].to_i,
18
+ number_of_replicas: ENV['POLIPUS_ELASTICSEACH_INDEX_REPLICAS'].to_i
19
+ }
20
+ )
21
+ mapping(_all: { enabled: false }) do
22
+ indexes(
23
+ :id,
24
+ index: :not_analyzed
25
+ )
26
+ indexes(
27
+ :body,
28
+ type: :string
29
+ )
30
+ indexes(
31
+ :code,
32
+ type: :integer
33
+ )
34
+ indexes(
35
+ :depth,
36
+ type: :integer
37
+ )
38
+ indexes(
39
+ :error,
40
+ type: :string
41
+ )
42
+ indexes(
43
+ :fetched,
44
+ type: :boolean
45
+ )
46
+ indexes(
47
+ :fetched_at,
48
+ type: :integer
49
+ )
50
+ indexes(
51
+ :headers,
52
+ type: :string
53
+ )
54
+ indexes(
55
+ :links,
56
+ type: :string
57
+ )
58
+ indexes(
59
+ :redirect_to,
60
+ type: :string
61
+ )
62
+ indexes(
63
+ :referer,
64
+ type: :string
65
+ )
66
+ indexes(
67
+ :response_time,
68
+ type: :integer
69
+ )
70
+ indexes(
71
+ :url,
72
+ type: :string
73
+ )
74
+ indexes(
75
+ :user_data,
76
+ type: :string
77
+ )
78
+ end
79
+
80
+ def self.client
81
+ __elasticsearch__.client
82
+ end
83
+
84
+ def self.count
85
+ client.count(index: index_name, type: document_type)['count'].to_i
86
+ end
87
+
88
+ def self.create_index!(name)
89
+ index_name(name) unless name.nil?
90
+ __elasticsearch__.create_index!(index: index_name)
91
+ end
92
+
93
+ def self.clear_index!
94
+ client.delete_by_query(
95
+ index: index_name,
96
+ body: { query: { match_all: {} } }
97
+ )
98
+ end
99
+
100
+ def self.delete_index!
101
+ client.indices.delete(index: index_name)
102
+ end
103
+
104
+ def self.exists?(id)
105
+ client.exists?(
106
+ index: index_name,
107
+ type: document_type,
108
+ id: id
109
+ )
110
+ end
111
+
112
+ def self.get(id)
113
+ return unless exists?(id)
114
+ client.get_source(
115
+ index: index_name,
116
+ type: document_type,
117
+ id: id
118
+ )
119
+ end
120
+
121
+ def self.index_exists?
122
+ client.indices.exists?(index: index_name)
123
+ end
124
+
125
+ def self.process_document(obj)
126
+ doc = { '_type' => document_type }
127
+ properties.each do |p|
128
+ doc[p.to_s] = obj.respond_to?(p.to_s) ? obj.send(p.to_s) : obj[p.to_s]
129
+ end
130
+ doc.reject { |_, value| value.nil? }
131
+ end
132
+
133
+ def self.properties
134
+ mapping.to_hash[document_type.to_sym][:properties].keys.map { |k| k.to_s }
135
+ end
136
+
137
+ def self.remove(id, refresh = false)
138
+ return unless exists?(id)
139
+ client.delete(
140
+ index: index_name,
141
+ type: document_type,
142
+ id: id,
143
+ refresh: refresh,
144
+ version: Time.now.to_i,
145
+ version_type: :external
146
+ )
147
+ end
148
+
149
+ def self.setup(client_)
150
+ __elasticsearch__.client = client_
151
+ end
152
+
153
+ def self.store(document, refresh = false)
154
+ document = process_document(document)
155
+ client.index(
156
+ index: index_name,
157
+ type: document_type,
158
+ id: document['id'],
159
+ body: document,
160
+ refresh: refresh,
161
+ version: document['fetched_at'].to_i,
162
+ version_type: :external
163
+ )
164
+ document['id']
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+ require 'base64'
3
+ require 'multi_json'
4
+ require 'polipus'
5
+ require 'polipus-elasticsearch'
6
+
7
+ module Polipus
8
+ module Storage
9
+ class ElasticSearchStore < Base
10
+ BINARY_FIELDS = %w(body headers user_data)
11
+ DEFAULT_INDEX = Polipus::ElasticSearch::Page
12
+
13
+ attr_accessor :index, :index_name, :except, :compress, :semaphore, :refresh
14
+
15
+ def initialize(client, options = {})
16
+ @index = options[:index] || options['index'] || DEFAULT_INDEX
17
+ @index_name = options[:index_name] || options['index_name']
18
+ @except = options[:except] || options['except'] || []
19
+ @compress = options[:compress] || options['compress']
20
+ @semaphore = Mutex.new
21
+ @refresh = options[:refresh] || options['refresh'] || true
22
+ index.setup(client)
23
+ index.create_index!(index_name) unless index.index_exists?
24
+ end
25
+
26
+ def add(page)
27
+ semaphore.synchronize do
28
+ obj = page.to_hash
29
+ Array(except).each { |field| obj.delete(field.to_s) }
30
+ BINARY_FIELDS.each do |field|
31
+ next if obj[field.to_s].nil? || obj[field.to_s].empty?
32
+ obj[field.to_s] = MultiJson.encode(obj[field.to_s]) if field.to_s == 'user_data'
33
+ obj[field.to_s] = Base64.encode64(obj[field.to_s])
34
+ end
35
+ obj['id'] = uuid(page)
36
+ obj['fetched_at'] = obj['fetched_at'].to_i
37
+ index.store(obj, refresh)
38
+ end
39
+ end
40
+
41
+ def clear
42
+ index.clear_index! if index.index_exists?
43
+ end
44
+
45
+ def count
46
+ index.count
47
+ end
48
+
49
+ def drop
50
+ index.delete_index! if index.index_exists?
51
+ end
52
+
53
+ def each
54
+ # This method is implemented only for testing purposes
55
+ response = index.client.search(
56
+ index: index_name,
57
+ body: {
58
+ query: { match_all: {} },
59
+ from: 0,
60
+ size: 25
61
+ }
62
+ )
63
+ response['hits']['hits'].each do |data|
64
+ page = load_page(data['_source'])
65
+ yield uuid(page), page
66
+ end
67
+ end
68
+
69
+ def exists?(page)
70
+ @semaphore.synchronize do
71
+ index.exists?(uuid(page))
72
+ end
73
+ end
74
+
75
+ def get(page)
76
+ @semaphore.synchronize do
77
+ load_page(index.get(uuid(page)))
78
+ end
79
+ end
80
+
81
+ def remove(page)
82
+ @semaphore.synchronize do
83
+ index.remove(uuid(page), refresh)
84
+ end
85
+ end
86
+
87
+ def load_page(data)
88
+ return nil if data.nil?
89
+ BINARY_FIELDS.each do |field|
90
+ next if data[field.to_s].nil? || data[field.to_s].empty?
91
+ data[field.to_s] = Base64.decode64(data[field.to_s])
92
+ data[field.to_s] = MultiJson.decode(data[field.to_s]) if field.to_s == 'user_data'
93
+ end
94
+ page = Page.from_hash(data)
95
+ page.fetched_at ||= 0
96
+ page
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,3 @@
1
+ # encoding: UTF-8
2
+ require 'polipus-elasticsearch/index/page'
3
+ require 'polipus-elasticsearch/storage/elasticsearch_store'
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'polipus-elasticsearch'
7
+ spec.version = '0.0.1'
8
+ spec.authors = ['Stefano Fontanelli']
9
+ spec.email = ['s.fontanelli@gmail.com']
10
+ spec.summary = 'Add support for ElasticSearch in Polipus crawler'
11
+ spec.description = 'Add support for ElasticSearch in Polipus crawler'
12
+ spec.homepage = 'https://github.com/stefanofontanelli/polipus-elasticsearch'
13
+ spec.license = 'MIT'
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
17
+ spec.require_paths = ['lib']
18
+ spec.add_runtime_dependency 'elasticsearch', '~> 1.0.4'
19
+ spec.add_runtime_dependency 'elasticsearch-model', '~> 0.1.4'
20
+ spec.add_runtime_dependency 'polipus', '~> 0.3', '>= 0.3.0'
21
+ spec.add_development_dependency 'rake', '~> 10.3'
22
+ spec.add_development_dependency 'rspec', '~> 3.1.0'
23
+ spec.add_development_dependency 'flexmock', '~> 1.3'
24
+ spec.add_development_dependency 'vcr', '~> 2.9.0'
25
+ spec.add_development_dependency 'webmock', '~> 1.20.0'
26
+ spec.add_development_dependency 'coveralls'
27
+ end
@@ -0,0 +1,175 @@
1
+ # encoding: UTF-8
2
+ require 'logger'
3
+ require 'polipus-elasticsearch'
4
+ require 'spec_helper'
5
+
6
+ describe Polipus::Storage::ElasticSearchStore do
7
+ before(:each)do
8
+ @logger = Logger.new(STDOUT)
9
+ @client = Elasticsearch::Client.new(host: '127.0.0.1', logger: @logger)
10
+ @client.transport.logger.level = Logger::INFO
11
+ @index_name = 'polipus_elasticsearch_test'
12
+ @storage = Polipus::Storage::ElasticSearchStore.new(
13
+ @client,
14
+ index_name: @index_name,
15
+ refresh: true
16
+ )
17
+ @storage_without_code_and_body = Polipus::Storage::ElasticSearchStore.new(
18
+ @client,
19
+ index_name: @index_name,
20
+ except: ['code', 'body'],
21
+ refresh: true
22
+ )
23
+ end
24
+
25
+ after(:each) do
26
+ @storage.drop
27
+ end
28
+
29
+ it 'should store a page' do
30
+ p = page_factory 'http://www.google.com'
31
+ uuid = @storage.add(p)
32
+ expect(uuid).to eq('ed646a3334ca891fd3467db131372140')
33
+ p = @storage.get(p)
34
+ expect(p).not_to be_nil
35
+ expect(p.url.to_s).to eq('http://www.google.com')
36
+ expect(p.body).to eq('<html></html>')
37
+ @storage.remove(p)
38
+ p = @storage.get(p)
39
+ expect(p).to be_nil
40
+ end
41
+
42
+ it 'should store all the relevant data from the page' do
43
+ url = "http://www.duckduckgo.com"
44
+ referer = "http://www.actually.nowhere.com"
45
+ redirectto = "#{url}/your_super_awesome_results?page=42"
46
+ now = Time.now.to_i
47
+ p = page_factory(
48
+ url,
49
+ {
50
+ referer: referer,
51
+ redirect_to: redirectto,
52
+ fetched_at: now
53
+ })
54
+ uuid = @storage.add p
55
+ expect(uuid).to eq('3cd657f53c74f22c1a21b420ce3863fd')
56
+ p = @storage.get p
57
+
58
+ expect(p.url.to_s).to eq(url)
59
+ expect(p.referer.to_s).to eq(referer)
60
+ expect(p.redirect_to.to_s).to eq(redirectto)
61
+ expect(p.fetched_at).to eq(now)
62
+ expect(p.body).to eq('<html></html>')
63
+
64
+ # for the sake of the other tests...
65
+ expect(@storage.remove(p)).to be_truthy
66
+ end
67
+
68
+ it 'should update a page' do
69
+ p = page_factory 'http://www.google.com', code: 301
70
+ @storage.add p
71
+ p = @storage.get p
72
+ expect(p.code).to eq(301)
73
+ end
74
+
75
+ it 'should iterate over stored pages' do
76
+ p = page_factory('http://www.google.com')
77
+ @storage.add(p)
78
+ @storage.each do |k, page|
79
+ expect(k).to eq('ed646a3334ca891fd3467db131372140')
80
+ expect(page.url.to_s).to eq('http://www.google.com')
81
+ end
82
+ end
83
+
84
+ it 'should delete a page' do
85
+ p = page_factory 'http://www.google.com', code: 301
86
+ @storage.remove p
87
+ expect(@storage.get(p)).to be_nil
88
+ end
89
+
90
+ it 'should store a page removing a query string from the uuid generation' do
91
+ p = page_factory 'http://www.asd.com/?asd=lol'
92
+ p_no_query = page_factory 'http://www.asd.com/?asdas=dasda&adsda=1'
93
+ @storage.include_query_string_in_uuid = false
94
+ @storage.add p
95
+ expect(@storage.exists?(p_no_query)).to be_truthy
96
+ @storage.remove p
97
+ end
98
+
99
+ it 'should store a page removing a query string from the uuid generation no ending slash' do
100
+ p = page_factory 'http://www.asd.com?asd=lol'
101
+ p_no_query = page_factory 'http://www.asd.com'
102
+ @storage.include_query_string_in_uuid = false
103
+ @storage.add p
104
+ expect(@storage.exists?(p_no_query)).to be_truthy
105
+ @storage.remove p
106
+ end
107
+
108
+ it 'should store a page with user data associated' do
109
+ p = page_factory 'http://www.user.com'
110
+ p.user_data.name = 'Test User Data'
111
+ @storage.add p
112
+ expect(@storage.exists?(p)).to be_truthy
113
+ p = @storage.get(p)
114
+ expect(p.user_data.name).to eq('Test User Data')
115
+ @storage.remove p
116
+ end
117
+
118
+ it 'should honor the except parameters' do
119
+ pag = page_factory 'http://www.user-doo.com'
120
+ expect(pag.code).to eq(200)
121
+ expect(pag.body).to eq('<html></html>')
122
+
123
+ @storage_without_code_and_body.add(pag)
124
+ pag = @storage_without_code_and_body.get(pag)
125
+
126
+ expect(pag.body).to be_nil
127
+ expect(pag.code).to eq(0)
128
+ @storage_without_code_and_body.remove(pag)
129
+ end
130
+
131
+ it 'should return false if a doc not exists' do
132
+ @storage.include_query_string_in_uuid = false
133
+ p_other = page_factory 'http://www.asdrrrr.com'
134
+ expect(@storage.exists?(p_other)).to be_falsey
135
+ @storage.add p_other
136
+ expect(@storage.exists?(p_other)).to be_truthy
137
+ p_other = page_factory 'http://www.asdrrrr.com?trk=asd-lol'
138
+ expect(@storage.exists?(p_other)).to be_truthy
139
+ @storage.include_query_string_in_uuid = true
140
+ expect(@storage.exists?(p_other)).to be_falsey
141
+ @storage.include_query_string_in_uuid = false
142
+ @storage.remove p_other
143
+ end
144
+
145
+ it 'should set page.fetched_at based on the id creation' do
146
+ p = page_factory 'http://www.user-doojo.com'
147
+ @storage.add p
148
+ expect(p.fetched_at).not_to be_nil
149
+ p = @storage.get p
150
+ expect(p.fetched_at).not_to be_nil
151
+ @storage.remove p
152
+ end
153
+
154
+ it 'should NOT set page.fetched_at if already present' do
155
+ p = page_factory 'http://www.user-doojooo.com'
156
+ p.fetched_at = 10
157
+ @storage.add p
158
+ p = @storage.get p
159
+ expect(p.fetched_at).to be 10
160
+ @storage.remove p
161
+ end
162
+
163
+ it 'should store two pages and the count will be two' do
164
+ pages = ['http://www.google.com', 'http://www.duckduckgo.com'].map do |url|
165
+ page_factory(url).tap do |page|
166
+ @storage.add(page)
167
+ end
168
+ end
169
+ expect(@storage.count).to be 2
170
+ pages.each do |page|
171
+ @storage.remove(page)
172
+ end
173
+ expect(@storage.count).to be 0
174
+ end
175
+ end
@@ -0,0 +1,51 @@
1
+ # Require this file using `require "spec_helper"`
2
+ # to ensure that it is only loaded once.
3
+ #
4
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
5
+ require 'digest/md5'
6
+ require 'coveralls'
7
+ require 'vcr'
8
+ require 'webmock/rspec'
9
+
10
+ Coveralls.wear!
11
+
12
+ require 'polipus'
13
+
14
+ VCR.configure do |c|
15
+ c.cassette_library_dir = "#{File.dirname(__FILE__)}/cassettes"
16
+ c.hook_into :webmock
17
+ c.allow_http_connections_when_no_cassette = true
18
+ c.ignore_localhost = true
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.run_all_when_everything_filtered = true
23
+ config.filter_run :focus
24
+
25
+ # Run specs in random order to surface order dependencies. If you find an
26
+ # order dependency and want to debug it, you can fix the order by providing
27
+ # the seed, which is printed after each run.
28
+ # --seed 1234
29
+ config.order = 'random'
30
+ config.mock_with :flexmock
31
+ config.around(:each) do |example|
32
+ t = Time.now
33
+ print example.metadata[:full_description]
34
+ VCR.use_cassette(
35
+ Digest::MD5.hexdigest(example.metadata[:full_description]),
36
+ record: :all
37
+ ) do
38
+ example.run
39
+ end
40
+ puts " [#{Time.now - t}s]"
41
+ end
42
+ config.before(:each) { Polipus::SignalHandler.disable }
43
+ end
44
+
45
+ def page_factory(url, params = {})
46
+ params[:code] ||= 200 unless params.has_key?(:code)
47
+ params[:body] = '<html></html>' unless params.has_key?(:body)
48
+ params[:fetched_at] = Time.now.to_i
49
+ sleep(1)
50
+ Polipus::Page.new(url, params)
51
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polipus-elasticsearch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stefano Fontanelli
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-07-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: elasticsearch
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: elasticsearch-model
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.1.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.1.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: polipus
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.3'
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: 0.3.0
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ~>
63
+ - !ruby/object:Gem::Version
64
+ version: '0.3'
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.3.0
68
+ - !ruby/object:Gem::Dependency
69
+ name: rake
70
+ requirement: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '10.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '10.3'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ version: 3.1.0
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ~>
98
+ - !ruby/object:Gem::Version
99
+ version: 3.1.0
100
+ - !ruby/object:Gem::Dependency
101
+ name: flexmock
102
+ requirement: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ~>
106
+ - !ruby/object:Gem::Version
107
+ version: '1.3'
108
+ type: :development
109
+ prerelease: false
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ~>
114
+ - !ruby/object:Gem::Version
115
+ version: '1.3'
116
+ - !ruby/object:Gem::Dependency
117
+ name: vcr
118
+ requirement: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ version: 2.9.0
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 2.9.0
132
+ - !ruby/object:Gem::Dependency
133
+ name: webmock
134
+ requirement: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ version: 1.20.0
140
+ type: :development
141
+ prerelease: false
142
+ version_requirements: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ~>
146
+ - !ruby/object:Gem::Version
147
+ version: 1.20.0
148
+ - !ruby/object:Gem::Dependency
149
+ name: coveralls
150
+ requirement: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ type: :development
157
+ prerelease: false
158
+ version_requirements: !ruby/object:Gem::Requirement
159
+ none: false
160
+ requirements:
161
+ - - ! '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ description: Add support for ElasticSearch in Polipus crawler
165
+ email:
166
+ - s.fontanelli@gmail.com
167
+ executables: []
168
+ extensions: []
169
+ extra_rdoc_files: []
170
+ files:
171
+ - .gitignore
172
+ - Gemfile
173
+ - LICENSE.txt
174
+ - README.md
175
+ - Rakefile
176
+ - lib/polipus-elasticsearch.rb
177
+ - lib/polipus-elasticsearch/index/page.rb
178
+ - lib/polipus-elasticsearch/storage/elasticsearch_store.rb
179
+ - polipus-elasticsearch.gemspec
180
+ - spec/polipus-elasticsearch/storage/elasticsearch_store_spec.rb
181
+ - spec/spec_helper.rb
182
+ homepage: https://github.com/stefanofontanelli/polipus-elasticsearch
183
+ licenses:
184
+ - MIT
185
+ post_install_message:
186
+ rdoc_options: []
187
+ require_paths:
188
+ - lib
189
+ required_ruby_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ! '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ segments:
196
+ - 0
197
+ hash: -3053519168912849089
198
+ required_rubygems_version: !ruby/object:Gem::Requirement
199
+ none: false
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ segments:
205
+ - 0
206
+ hash: -3053519168912849089
207
+ requirements: []
208
+ rubyforge_project:
209
+ rubygems_version: 1.8.23.2
210
+ signing_key:
211
+ specification_version: 3
212
+ summary: Add support for ElasticSearch in Polipus crawler
213
+ test_files:
214
+ - spec/polipus-elasticsearch/storage/elasticsearch_store_spec.rb
215
+ - spec/spec_helper.rb