elastics 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31208a61d960f7b411e4b6588d8c7aa2f8741e59
4
+ data.tar.gz: 64d46d44db05a22ac1d84a5155cb5ea6489327aa
5
+ SHA512:
6
+ metadata.gz: 998636cd31b1a9229d381544206fb3a17e4c7bef3ba6d4b26935e7d7254e55ab545a8247668063a61b64979115d3332cb1bd7f83fa1c95d3123ec1ab10b3b987
7
+ data.tar.gz: 7be4cb9870cd5cc3e053f492fd55479e1ab41287790047987b9897430d8dddab3ba2b8e3689038cd04e8361a00383d082fd2b66b1625cce82a734b584abf0ec1
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,19 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ elastics (0.1.0)
5
+ httpclient (~> 2.4.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ httpclient (2.4.0)
11
+ rake (10.3.2)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.5)
18
+ elastics!
19
+ rake (~> 10)
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # elastics
2
+
3
+ Simple ElasticSearch client.
4
+
5
+ Fast and thread-safe [httpclient](https://github.com/nahi/httpclient) under the hood.
6
+
7
+ ## Install
8
+
9
+ ```ruby
10
+ # Gemfile
11
+ gem 'elastics', github: 'printercu/elastics-rb'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ### Plain
17
+
18
+ ```ruby
19
+ # initialize client with
20
+ client = Elastics::Client.new(options)
21
+ # options is hash with
22
+ # :host
23
+ # :port
24
+ # :index - (default index)
25
+ # :type - (default type)
26
+
27
+ # basic request
28
+ client.request(options)
29
+ # options is hash with
30
+ # :method - default :get
31
+ # :data - post body
32
+ # :query - query string params
33
+ # :index, :type, :id - query path params to override defaults
34
+
35
+ # method shortcuts for #put, #post #delete
36
+ client.delete(params)
37
+
38
+ # getter/setter shortcuts
39
+ client.set(id, data)
40
+ client.get(id)
41
+ client.get(params) # as usual
42
+
43
+ # other shortcuts (set method & id)
44
+ client.put_mapping(index: index, type: type, data: mapping)
45
+ client.search(params)
46
+ client.index(params) # PUT if :id is set, otherwise POST
47
+
48
+ # utils
49
+ client.index_exists?(name)
50
+ ```
51
+
52
+ ### ActiveRecord
53
+
54
+ ```ruby
55
+ class User < ActiveRecord::Base
56
+ indexed_with_elastics
57
+ # optionally pass :index, :type
58
+
59
+ # optionally override to export only selected fields
60
+ def to_elastics
61
+ serializable_hash(only: [:id, :first_name, :last_name])
62
+ end
63
+ end
64
+
65
+ User.search_elastics(data)
66
+ ```
67
+
68
+ #### Configure
69
+ ```yml
70
+ # database.yml
71
+ development:
72
+ elastics:
73
+ # use single index (app_dev/users, app_dev/documents)
74
+ index: app_dev
75
+
76
+ # use index per type (app_dev_users/users, app_dev_documents/documents)
77
+ index_prefix: app_dev_
78
+
79
+ production:
80
+ elastics:
81
+ host: 10.0.0.1
82
+ port: 1234
83
+
84
+ index: app
85
+ # or
86
+ index_prefix: app_
87
+ ```
88
+
89
+ #### Mappings & index settings
90
+ Mappings & index settings `.yml` files are placed in
91
+ `db/elastics/mappings` & `db/elastics/indices`.
92
+ For now this files are not related to models and only used by rake tasks.
93
+
94
+ - `rake elastics:create` (or `Elastics::Tasks.create_indices`)
95
+ creates index with settings for each file from `indices` folder.
96
+ For single index it only processes file with index name.
97
+ For multiple indices each index name is `#{index_prefix}#{file.basename}`
98
+
99
+ - `rake elastics:migrate` (or `Elastics::Tasks.migrate`)
100
+ puts mappings from `mappings` folder.
101
+
102
+ ## License
103
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib/elastics'
6
+ t.libs << 'test'
7
+ t.test_files = FileList['test/lib/elastics/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task default: :test
data/elastics.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elastics/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'elastics'
8
+ spec.version = Elastics::VERSION
9
+ spec.authors = ['Max Melentiev']
10
+ spec.email = ['melentievm@gmail.com']
11
+ spec.summary = 'ElasticSearch client with ActiveRecord integration'
12
+ spec.description = 'Lightweight and extensible elasticsearch client'
13
+ spec.homepage = 'http://github.com/printercu/elastics-rb'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'httpclient', '~> 2.4.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.5'
24
+ spec.add_development_dependency 'rake', '~> 10'
25
+ end
@@ -0,0 +1,59 @@
1
+ module Elastics
2
+ module ActiveRecord
3
+ module HelperMethods
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def search(data = {}, routing = nil)
8
+ es_results = search_elastics(data, routing)
9
+ ids = es_results['hits'.freeze]['hits'.freeze].map { |x| x['_id'.freeze].to_i }
10
+ relation = where(id: ids)
11
+ items_by_id = relation.index_by(&:id)
12
+ collection = ids.map { |i| items_by_id[i] }
13
+ {
14
+ collection: collection,
15
+ relation: relation,
16
+ search: es_results,
17
+ }
18
+ end
19
+
20
+ def search_elastics(data = {}, routing = nil)
21
+ request = {
22
+ id: :_search,
23
+ data: data,
24
+ }
25
+ request[:query] = {routing: routing} if routing
26
+ request_elastics(request)
27
+ end
28
+
29
+ def request_elastics(params)
30
+ request = {
31
+ index: elastics_index_name,
32
+ type: elastics_type_name,
33
+ }.merge!(params)
34
+ elastics.request(request)
35
+ end
36
+
37
+ def elastics_mapping
38
+ request_elastics(method: :get, id: :_mapping)
39
+ end
40
+
41
+ def reindex(*args)
42
+ find_each(*args, &:index_elastics)
43
+ end
44
+ end
45
+
46
+ def index_elastics
47
+ self.class.request_elastics(method: :post, id: id, data: to_elastics)
48
+ end
49
+
50
+ def delete_elastics
51
+ self.class.request_elastics(method: :delete, id: id)
52
+ end
53
+
54
+ def to_elastics
55
+ as_json
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ module Elastics
2
+ module ActiveRecord
3
+ module Instrumentation
4
+ def request_elastics(params = {})
5
+ data = {
6
+ name: name,
7
+ request: params,
8
+ }
9
+ ActiveSupport::Notifications.instrument 'request_elastics.active_record', data do
10
+ super(params)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module Elastics
2
+ module ActiveRecord
3
+ module LogSubscriber
4
+ def self.included(base)
5
+ instance_methods.each { |method| base.method_added(method) }
6
+ end
7
+
8
+ def request_elastics(event)
9
+ return unless logger.debug?
10
+
11
+ payload = event.payload
12
+
13
+ name = "#{payload[:name]} elastics (#{event.duration.round(1)}ms)"
14
+ request = payload[:request].to_json
15
+
16
+ if odd?
17
+ name = color(name, ActiveSupport::LogSubscriber::CYAN, true)
18
+ request = color(request, nil, true)
19
+ else
20
+ name = color(name, ActiveSupport::LogSubscriber::MAGENTA, true)
21
+ end
22
+
23
+ debug " #{name} #{request}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ module Elastics
2
+ module ActiveRecord
3
+ module ModelSchema
4
+ attr_writer :elastics_index_name, :elastics_type_name
5
+
6
+ def elastics_index_name
7
+ reset_elastics_index_name unless defined?(@elastics_index_name)
8
+ @elastics_index_name
9
+ end
10
+
11
+ def elastics_type_name
12
+ reset_elastics_index_name unless defined?(@elastics_type_name)
13
+ @elastics_type_name
14
+ end
15
+
16
+ def reset_elastics_index_name
17
+ superclass_responds = superclass.respond_to?(:elastics_index_name)
18
+ index = if abstract_class? && superclass_responds
19
+ superclass == ::ActiveRecord::Base ? nil : superclass.elastics_index_name
20
+ elsif superclass.abstract_class? && superclass_responds
21
+ superclass.elastics_index_name || compute_elastics_index_name
22
+ else
23
+ compute_elastics_index_name
24
+ end
25
+ @elastics_index_name = index
26
+ @elastics_type_name = compute_elastics_type_name
27
+ end
28
+
29
+ def compute_elastics_index_name(name = nil)
30
+ elastics_config[:index] ||
31
+ "#{elastics_config[:index_prefix]}#{name || table_name.singularize}"
32
+ end
33
+
34
+ def compute_elastics_type_name
35
+ model_name.to_s.demodulize.underscore.singularize
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ module Elastics
2
+ module ActiveRecord
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :ModelSchema
6
+ autoload :HelperMethods
7
+ autoload :Instrumentation
8
+ autoload :LogSubscriber
9
+
10
+ def elastics_config
11
+ @elastics_config ||= connection_config[:elastics].try!(:with_indifferent_access) ||
12
+ raise('No elastics configuration in database.yml')
13
+ end
14
+
15
+ def elastics
16
+ @elastics ||= Client.new elastics_config.slice(:host, :port)
17
+ end
18
+
19
+ def indexed_with_elastics(options = {})
20
+ options = {
21
+ hooks: [:update, :destroy],
22
+ }.merge(options)
23
+
24
+ extend ModelSchema
25
+ include HelperMethods
26
+ extend Instrumentation
27
+
28
+ self.elastics_index_name = options[:index] if options[:index]
29
+ self.elastics_type_name = options[:type] if options[:type]
30
+
31
+ hooks = options[:hooks]
32
+ after_commit :index_elastics, on: [:create, :update] if hooks.include?(:update)
33
+ after_commit :delete_elastics, on: [:destroy] if hooks.include?(:destroy)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,97 @@
1
+ require 'httpclient'
2
+
3
+ module Elastics
4
+ class Client
5
+ HEADERS = {'Content-Type' => 'application/json'}
6
+
7
+ attr_writer :index, :type
8
+ attr_reader :client
9
+
10
+ def initialize(defaults = {})
11
+ @host = defaults[:host] || '127.0.0.1'
12
+ @port = defaults[:port] || 9200
13
+ @index = defaults[:index]
14
+ @type = defaults[:type]
15
+ @client = HTTPClient.new
16
+ end
17
+
18
+ def debug!(dev = STDOUT)
19
+ @client.debug_dev = dev
20
+ end
21
+
22
+ def debug_off!
23
+ @client.debug_dev = nil
24
+ end
25
+
26
+ def set_index(index, type = nil)
27
+ @index = index || nil
28
+ @type = type || nil
29
+ end
30
+
31
+ def uri(params)
32
+ str = "http://#{@host}:#{@port}"
33
+ if index = params[:index] || @index
34
+ str += "/#{index}"
35
+ type = params[:type] || @type
36
+ str += "/#{type}" if type
37
+ end
38
+ path = params[:id]
39
+ str += "/#{path}" if path
40
+ str
41
+ end
42
+
43
+ def request(params)
44
+ http_method = params[:method] || :get
45
+ body = params[:data].try!(:to_json)
46
+ res = @client.request(http_method, uri(params), params[:query], body, HEADERS)
47
+ status = res.status
48
+ return JSON.parse(res.body) if 300 > status
49
+ if 404 == status
50
+ message = JSON.parse(res.body)['error'] rescue 'Not found'
51
+ raise NotFound, message
52
+ end
53
+ raise Error.new(res.reason)
54
+ end
55
+
56
+ # shortcuts
57
+ [:put, :post, :delete].each do |method|
58
+ define_method(method) do |params|
59
+ params[:method] = method
60
+ request params
61
+ end
62
+ end
63
+
64
+ def get(params)
65
+ params = {id: params} unless params.is_a?(Hash)
66
+ params[:method] = :get
67
+ request(params)
68
+ end
69
+
70
+ def set(id, data)
71
+ request(id: id, data: data, method: :put)
72
+ end
73
+
74
+ def put_mapping(params)
75
+ params[:id] = :_mapping
76
+ params[:method] = :put
77
+ request(params)
78
+ end
79
+
80
+ def search(params)
81
+ params[:id] = :_search
82
+ params[:method] = :post
83
+ request(params)
84
+ end
85
+
86
+ def index(params)
87
+ params[:id] ? put(params) : post(params)
88
+ end
89
+
90
+ def index_exists?(index)
91
+ get(index: index, type: nil, id: :_mapping)
92
+ true
93
+ rescue NotFound
94
+ false
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,27 @@
1
+ module Elastics
2
+ module QueryHelper
3
+ def normalize_filters(filters)
4
+ return filters unless filters.is_a?(Array)
5
+ return filters[0] if 2 > filters.size
6
+ {and: {filters: filters}}
7
+ end
8
+
9
+ def normalize_query(query, filters)
10
+ filter = normalize_filters filters
11
+ query ||= {match_all: {}}
12
+ return query unless filter
13
+ {filtered: {
14
+ query: query,
15
+ filter: filter,
16
+ }}
17
+ end
18
+
19
+ def terms_query(field, val, options = {})
20
+ if val.is_a?(Array)
21
+ {terms: {field => val}.merge(options)}
22
+ else
23
+ result = {term: {field => val}}
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ require 'elastics/active_record'
2
+
3
+ module Elastics
4
+ class Railtie < Rails::Railtie
5
+ initializer 'elastics.configure_rails_initialization' do
6
+ ::ActiveRecord::Base.extend Elastics::ActiveRecord
7
+ unless ::ActiveRecord::LogSubscriber < ActiveRecord::LogSubscriber
8
+ ::ActiveRecord::LogSubscriber.send :include, ActiveRecord::LogSubscriber
9
+ end
10
+ end
11
+
12
+ rake_tasks do
13
+ load 'tasks/elastics.rake'
14
+ end
15
+ end
16
+ end
17
+
18
+ Elastics::Railtie.run_initializers
@@ -0,0 +1,42 @@
1
+ module Elastics
2
+ module Tasks
3
+ module Indices
4
+ attr_writer :indices_path
5
+
6
+ def indices_paths
7
+ @indices_paths ||= base_paths.map { |x| File.join x, 'indices' }
8
+ end
9
+
10
+ def indices_settings
11
+ @indices_settings ||= indices_paths.map { |path| Dir["#{path}/*.yml"] }.
12
+ flatten.sort.
13
+ each_with_object({}) do |file, hash|
14
+ name = File.basename file, '.yml'
15
+ data = YAML.load_file(file)
16
+ name = "#{config[:index_prefix]}#{name}"
17
+ hash[name] = data[Rails.env] || data
18
+ end
19
+ end
20
+
21
+ def indices
22
+ @indices ||= config[:index] ? [config[:index]] : indices_settings.keys
23
+ end
24
+
25
+ def delete_indices
26
+ indices.each do |index|
27
+ log "Delete index #{index}"
28
+ client.delete index: index rescue NotFound
29
+ end
30
+ end
31
+
32
+ def create_indices
33
+ indices.each do |index|
34
+ log "Create index #{index}"
35
+ unless client.index_exists?(index)
36
+ client.put(index: index, data: indices_settings[index])
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ module Elastics
2
+ module Tasks
3
+ module Mappings
4
+ attr_writer :mappings_path
5
+
6
+ def mappings_paths
7
+ @mappings_paths ||= base_paths.map { |x| File.join x, 'mappings' }
8
+ end
9
+
10
+ def put_mappings
11
+ mappings.each do |type, mapping|
12
+ index = index_for_type(type)
13
+ log "Put mapping #{index}/#{type}"
14
+ client.put_mapping index: index, type: type, data: mapping
15
+ end
16
+ end
17
+
18
+ def mappings
19
+ @mappings ||= mappings_paths.map { |path| Dir["#{path}/*.yml"] }.
20
+ flatten.sort.
21
+ each_with_object({}) do |file, hash|
22
+ name = File.basename file, '.yml'
23
+ hash[name] = YAML.load_file(file)
24
+ end
25
+ end
26
+
27
+ def types
28
+ @types ||= mappings.keys
29
+ end
30
+
31
+ def indices
32
+ @indices ||= (super + types.map { |type| index_for_type(type) }).uniq
33
+ end
34
+
35
+ def index_for_type(type)
36
+ config[:index] || "#{config[:index_prefix]}#{type}"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ module Elastics
2
+ module Tasks
3
+ require 'elastics/tasks/indices'
4
+ include Indices
5
+
6
+ require 'elastics/tasks/mappings'
7
+ include Mappings
8
+
9
+ extend self
10
+
11
+ attr_writer :base_paths, :client, :config
12
+
13
+ def base_paths
14
+ @base_paths ||= [File.join(Rails.root, 'db', 'elastics')]
15
+ end
16
+
17
+ def migrate(options = {})
18
+ delete_indices if options[:flush]
19
+ create_indices
20
+ put_mappings
21
+ end
22
+
23
+ def client
24
+ @client ||= ::ActiveRecord::Base.elastics
25
+ end
26
+
27
+ def config
28
+ @config ||= ::ActiveRecord::Base.elastics_config
29
+ end
30
+
31
+ def log(*args)
32
+ Rails.logger.info(*args)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Elastics
2
+ VERSION = '0.1.0'
3
+
4
+ def self.gem_version
5
+ Gem::Version.new VERSION
6
+ end
7
+ end
data/lib/elastics.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Elastics
2
+ class Error < StandardError; end
3
+ class NotFound < Error; end
4
+
5
+ require 'elastics/client'
6
+ require 'elastics/query_helper'
7
+
8
+ autoload :Tasks, 'elastics/tasks'
9
+
10
+ extend QueryHelper
11
+ end
12
+
13
+ require 'elastics/railtie' if defined?(Rails)
@@ -0,0 +1,20 @@
1
+ namespace 'elastics' do
2
+ task load_config: [:environment, 'db:load_config'] do
3
+ end
4
+
5
+ desc 'Creates indices and applies mappings (Use NOFLUSH to prevent old indices from deletion)'
6
+ task migrate: :load_config do
7
+ flush = !ENV.key?('NOFLUSH')
8
+ Elastics::Tasks.migrate(flush: flush)
9
+ end
10
+
11
+ desc 'Creates indices'
12
+ task create: :load_config do
13
+ Elastics::Tasks.create_indices
14
+ end
15
+
16
+ desc 'Drops indices'
17
+ task delete: :load_config do
18
+ Elastics::Tasks.delete_indices
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elastics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Max Melentiev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpclient
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10'
55
+ description: Lightweight and extensible elasticsearch client
56
+ email:
57
+ - melentievm@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - Gemfile.lock
64
+ - README.md
65
+ - Rakefile
66
+ - elastics.gemspec
67
+ - lib/elastics.rb
68
+ - lib/elastics/active_record.rb
69
+ - lib/elastics/active_record/helper_methods.rb
70
+ - lib/elastics/active_record/instrumentation.rb
71
+ - lib/elastics/active_record/log_subscriber.rb
72
+ - lib/elastics/active_record/model_schema.rb
73
+ - lib/elastics/client.rb
74
+ - lib/elastics/query_helper.rb
75
+ - lib/elastics/railtie.rb
76
+ - lib/elastics/tasks.rb
77
+ - lib/elastics/tasks/indices.rb
78
+ - lib/elastics/tasks/mappings.rb
79
+ - lib/elastics/version.rb
80
+ - lib/tasks/elastics.rake
81
+ homepage: http://github.com/printercu/elastics-rb
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.2.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: ElasticSearch client with ActiveRecord integration
105
+ test_files: []