searchkick 3.1.3 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8fb08ed2716d410bb1d609e873e10387a97e437a6bb63530687998a5b9539e13
4
- data.tar.gz: f0b43190746e1d841643b1fc45ef8cd86621b42970369cb2c5fb5f02396ca432
3
+ metadata.gz: 7e1a7c30f19f80bab77d1c44dc8778877881d8178ab52c2c3e48cb0fe1f31ac4
4
+ data.tar.gz: 3091f32cea77c628e629e28dc865d700203f2265393ff44526e86b8ce899ae46
5
5
  SHA512:
6
- metadata.gz: a15444ee63e976df8b85dfb5c5462f48525cd7eb102dc4d0f156e92937223d2cae116c66019821009291bbaeaad56449bf145861c47fa2b729c13e6cf9cf13ac
7
- data.tar.gz: cff5bee77c65345926199f94ba975db417bbbdcca5cfa7647e004b99c5f7aba3965da700a039f7bd1906d91734de98edcc178dcebfe303a4fa8b7b67bdd3e1dd
6
+ metadata.gz: 8d25cc6e9ac21a3f62199255aa5ab9911f2ab3fd970d79417a29063eeb944497da84e1db5ba840cc75eba549bee524c2a9b5b68d624dcadf0d4aa9bfcbc6f4fd
7
+ data.tar.gz: 9fff1372bb24c8c8d2a59a1821d5ad299c9fcc1e2a73e53bbda2f3fec6b8aeddff0e00692451ec3ece0708762b9ccafe370b0ca7fc2d1e623a5bf12688a78ecd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 4.0.0
2
+
3
+ - Added support for Elasticsearch 7
4
+ - Added `models` option
5
+
6
+ Breaking changes
7
+
8
+ - Removed support for Elasticsearch 5
9
+ - Removed support for multi-word synonyms (they no longer work with shingles)
10
+
1
11
  ## 3.1.3
2
12
 
3
13
  - Added support for endless ranges
data/README.md CHANGED
@@ -53,7 +53,7 @@ Add this line to your application’s Gemfile:
53
53
  gem 'searchkick'
54
54
  ```
55
55
 
56
- The latest version works with Elasticsearch 5 and 6. For Elasticsearch 2, use version 2.5.0 and [this readme](https://github.com/ankane/searchkick/blob/v2.5.0/README.md).
56
+ The latest version works with Elasticsearch 6 and 7. For Elasticsearch 5, use version 3.1.3 and [this readme](https://github.com/ankane/searchkick/blob/v3.1.3/README.md).
57
57
 
58
58
  Add searchkick to models you want to search.
59
59
 
@@ -312,13 +312,13 @@ A few languages require plugins:
312
312
 
313
313
  ```ruby
314
314
  class Product < ApplicationRecord
315
- searchkick synonyms: [["scallion", "green onion"], ["qtip", "cotton swab"]]
315
+ searchkick synonyms: [["burger", "hamburger"], ["sneakers", "shoes"]]
316
316
  end
317
317
  ```
318
318
 
319
319
  Call `Product.reindex` after changing synonyms.
320
320
 
321
- Synonyms cannot be more than two words at the moment.
321
+ Synonyms cannot be multiple words at the moment.
322
322
 
323
323
  To read synonyms from a file, use:
324
324
 
@@ -355,27 +355,6 @@ Search with:
355
355
  Product.search query, fields: [:name_tagged]
356
356
  ```
357
357
 
358
- ### WordNet
359
-
360
- Prepopulate English synonyms with the [WordNet database](https://en.wikipedia.org/wiki/WordNet).
361
-
362
- Download [WordNet 3.0](http://wordnetcode.princeton.edu/3.0/WNprolog-3.0.tar.gz) to each Elasticsearch server and move `wn_s.pl` to the `/var/lib` directory.
363
-
364
- ```sh
365
- cd /tmp
366
- curl -o wordnet.tar.gz http://wordnetcode.princeton.edu/3.0/WNprolog-3.0.tar.gz
367
- tar -zxvf wordnet.tar.gz
368
- mv prolog/wn_s.pl /var/lib
369
- ```
370
-
371
- Tell each model to use it:
372
-
373
- ```ruby
374
- class Product < ApplicationRecord
375
- searchkick wordnet: true
376
- end
377
- ```
378
-
379
358
  ### Misspellings
380
359
 
381
360
  By default, Searchkick handles misspelled queries by returning results with an [edit distance](https://en.wikipedia.org/wiki/Levenshtein_distance) of one.
@@ -796,8 +775,6 @@ Script support
796
775
  Product.search "*", aggs: {color: {script: {source: "'Color: ' + _value"}}}
797
776
  ```
798
777
 
799
- **Note:** Use `inline` instead of `source` before Elasticsearch 5.6
800
-
801
778
  Date histogram
802
779
 
803
780
  ```ruby
@@ -924,9 +901,7 @@ You can also index and search geo shapes.
924
901
 
925
902
  ```ruby
926
903
  class Restaurant < ApplicationRecord
927
- searchkick geo_shape: {
928
- bounds: {tree: "geohash", precision: "1km"}
929
- }
904
+ searchkick geo_shape: [:bounds]
930
905
 
931
906
  def search_data
932
907
  attributes.merge(
@@ -959,12 +934,6 @@ Not touching the query shape
959
934
  Restaurant.search "burger", where: {bounds: {geo_shape: {type: "envelope", relation: "disjoint", coordinates: [{lat: 38, lon: -123}, {lat: 37, lon: -122}]}}}
960
935
  ```
961
936
 
962
- Containing the query shape
963
-
964
- ```ruby
965
- Restaurant.search "fries", where: {bounds: {geo_shape: {type: "envelope", relation: "contains", coordinates: [{lat: 38, lon: -123}, {lat: 37, lon: -122}]}}}
966
- ```
967
-
968
937
  ## Inheritance
969
938
 
970
939
  Searchkick supports single table inheritance.
@@ -1496,21 +1465,15 @@ Then use `products` and `coupons` as typical results.
1496
1465
 
1497
1466
  **Note:** Errors are not raised as with single requests. Use the `error` method on each query to check for errors.
1498
1467
 
1499
- ## Multiple Indices
1468
+ ## Multiple Models
1500
1469
 
1501
- Search across multiple models/indices with:
1470
+ Search across multiple models with:
1502
1471
 
1503
1472
  ```ruby
1504
- Searchkick.search "milk", index_name: [Product, Category]
1473
+ Searchkick.search "milk", models: [Product, Category]
1505
1474
  ```
1506
1475
 
1507
- Specify conditions for different indices
1508
-
1509
- ```ruby
1510
- where: {_or: [{_type: "product", in_stock: true}, {_type: "category", active: true}]}
1511
- ```
1512
-
1513
- Boost specific indices with:
1476
+ Boost specific models with:
1514
1477
 
1515
1478
  ```ruby
1516
1479
  indices_boost: {Category => 2, Product => 1}
@@ -1657,7 +1620,7 @@ Product.search "milk", includes: [:brand, :stores]
1657
1620
  Eager load different associations by model
1658
1621
 
1659
1622
  ```ruby
1660
- Searchkick.search("*", index_name: [Product, Store], model_includes: {Product => [:store], Store => [:product]})
1623
+ Searchkick.search("*", models: [Product, Store], model_includes: {Product => [:store], Store => [:product]})
1661
1624
  ```
1662
1625
 
1663
1626
  Run additional scopes on results
@@ -1900,6 +1863,11 @@ Check out [this great post](https://www.tiagoamaro.com.br/2014/12/11/multi-tenan
1900
1863
 
1901
1864
  See [how to upgrade to Searchkick 3](docs/Searchkick-3-Upgrade.md)
1902
1865
 
1866
+ ## Elasticsearch 6 to 7 Upgrade
1867
+
1868
+ 1. Install Searchkick 4
1869
+ 2. Upgrade your Elasticsearch cluster
1870
+
1903
1871
  ## Elasticsearch 5 to 6 Upgrade
1904
1872
 
1905
1873
  Elasticsearch 6 removes the ability to reindex with the `_all` field. Before you upgrade, we recommend disabling this field manually and specifying default fields on your models.
data/lib/searchkick.rb CHANGED
@@ -78,16 +78,36 @@ module Searchkick
78
78
  Gem::Version.new(server_version.split("-")[0]) < Gem::Version.new(version.split("-")[0])
79
79
  end
80
80
 
81
+ # memoize for performance
82
+ def self.server_below7?
83
+ unless defined?(@server_below7)
84
+ @server_below7 = server_below?("7.0.0")
85
+ end
86
+ @server_below7
87
+ end
88
+
81
89
  def self.search(term = "*", model: nil, **options, &block)
82
90
  options = options.dup
83
91
  klass = model
84
92
 
85
- # make Searchkick.search(index_name: [Product]) and Product.search equivalent
93
+ # convert index_name into models if possible
94
+ # this should allow for easier upgrade
95
+ if options[:index_name] && !options[:models] && Array(options[:index_name]).all? { |v| v.respond_to?(:searchkick_index) }
96
+ options[:models] = options.delete(:index_name)
97
+ end
98
+
99
+ # make Searchkick.search(models: [Product]) and Product.search equivalent
86
100
  unless klass
87
- index_name = Array(options[:index_name])
88
- if index_name.size == 1 && index_name.first.respond_to?(:searchkick_index)
89
- klass = index_name.first
90
- options.delete(:index_name)
101
+ models = Array(options[:models])
102
+ if models.size == 1
103
+ klass = models.first
104
+ options.delete(:models)
105
+ end
106
+ end
107
+
108
+ if klass
109
+ if (options[:models] && Array(options[:models]) != [klass]) || Array(options[:index_name]).any? { |v| v.respond_to?(:searchkick_index) && v != klass }
110
+ raise ArgumentError, "Use Searchkick.search to search multiple models"
91
111
  end
92
112
  end
93
113
 
@@ -17,7 +17,7 @@ module Searchkick
17
17
  end
18
18
 
19
19
  def delete
20
- if !Searchkick.server_below?("6.0.0") && alias_exists?
20
+ if alias_exists?
21
21
  # can't call delete directly on aliases in ES 6
22
22
  indices = client.indices.get_alias(name: name).keys
23
23
  client.indices.delete index: indices
@@ -68,7 +68,7 @@ module Searchkick
68
68
  }
69
69
  )
70
70
 
71
- response["hits"]["total"]
71
+ Searchkick::Results.new(nil, response).total_count
72
72
  end
73
73
 
74
74
  def promote(new_name, update_refresh_interval: false)
@@ -4,15 +4,13 @@ module Searchkick
4
4
  options = @options
5
5
  language = options[:language]
6
6
  language = language.call if language.respond_to?(:call)
7
- index_type = options[:_type]
8
- index_type = index_type.call if index_type.respond_to?(:call)
9
7
 
10
8
  if options[:mappings] && !options[:merge_mappings]
11
9
  settings = options[:settings] || {}
12
10
  mappings = options[:mappings]
13
11
  else
14
- below60 = Searchkick.server_below?("6.0.0")
15
12
  below62 = Searchkick.server_below?("6.2.0")
13
+ below70 = Searchkick.server_below?("7.0.0")
16
14
 
17
15
  default_type = "text"
18
16
  default_analyzer = :searchkick_index
@@ -144,15 +142,6 @@ module Searchkick
144
142
  }
145
143
  }
146
144
 
147
- if below60
148
- # ES docs say standard token filter does nothing in ES 5
149
- # (and therefore isn't needed at at), but tests say otherwise
150
- # https://www.elastic.co/guide/en/elasticsearch/reference/5.0/analysis-standard-tokenfilter.html
151
- [default_analyzer, :searchkick_search, :searchkick_search2].each do |analyzer|
152
- settings[:analysis][:analyzer][analyzer][:filter].unshift("standard")
153
- end
154
- end
155
-
156
145
  stem = options[:stem]
157
146
 
158
147
  case language
@@ -279,8 +268,7 @@ module Searchkick
279
268
  # - Only apply the synonym expansion at index time
280
269
  # - Don't have the synonym filter applied search
281
270
  # - Use directional synonyms where appropriate. You want to make sure that you're not injecting terms that are too general.
282
- settings[:analysis][:analyzer][default_analyzer][:filter].insert(4, "searchkick_synonym") if below60
283
- settings[:analysis][:analyzer][default_analyzer][:filter] << "searchkick_synonym"
271
+ settings[:analysis][:analyzer][default_analyzer][:filter].insert(2, "searchkick_synonym")
284
272
 
285
273
  %w(word_start word_middle word_end).each do |type|
286
274
  settings[:analysis][:analyzer]["searchkick_#{type}_index".to_sym][:filter].insert(2, "searchkick_synonym")
@@ -391,10 +379,6 @@ module Searchkick
391
379
  "{name}" => keyword_mapping
392
380
  }
393
381
 
394
- if below60 && all
395
- dynamic_fields["{name}"][:include_in_all] = !options[:searchable]
396
- end
397
-
398
382
  if options.key?(:filterable)
399
383
  dynamic_fields["{name}"] = {type: default_type, index: index_false_value}
400
384
  end
@@ -413,25 +397,24 @@ module Searchkick
413
397
  multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
414
398
 
415
399
  mappings = {
416
- index_type => {
417
- properties: mapping,
418
- _routing: routing,
419
- # https://gist.github.com/kimchy/2898285
420
- dynamic_templates: [
421
- {
422
- string_template: {
423
- match: "*",
424
- match_mapping_type: "string",
425
- mapping: multi_field
426
- }
400
+ properties: mapping,
401
+ _routing: routing,
402
+ # https://gist.github.com/kimchy/2898285
403
+ dynamic_templates: [
404
+ {
405
+ string_template: {
406
+ match: "*",
407
+ match_mapping_type: "string",
408
+ mapping: multi_field
427
409
  }
428
- ]
429
- }
410
+ }
411
+ ]
430
412
  }
431
413
 
432
- if below60
433
- all_enabled = all && (!options[:searchable] || options[:searchable].to_a.map(&:to_s).include?("_all"))
434
- mappings[index_type][:_all] = all_enabled ? analyzed_field_options : {enabled: false}
414
+ if below70
415
+ index_type = options[:_type]
416
+ index_type = index_type.call if index_type.respond_to?(:call)
417
+ mappings = {index_type => mappings}
435
418
  end
436
419
 
437
420
  mappings = mappings.symbolize_keys.deep_merge((options[:mappings] || {}).symbolize_keys)
@@ -18,7 +18,7 @@ module Searchkick
18
18
  unknown_keywords = options.keys - [:aggs, :block, :body, :body_options, :boost,
19
19
  :boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :execute, :explain,
20
20
  :fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load,
21
- :match, :misspellings, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile,
21
+ :match, :misspellings, :models, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile,
22
22
  :request_params, :routing, :scope_results, :select, :similar, :smart_aggs, :suggest, :total_entries, :track, :type, :where]
23
23
  raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
24
24
 
@@ -39,6 +39,7 @@ module Searchkick
39
39
  @misspellings = false
40
40
  @misspellings_below = nil
41
41
  @highlighted_fields = nil
42
+ @index_mapping = nil
42
43
 
43
44
  prepare
44
45
  end
@@ -56,9 +57,18 @@ module Searchkick
56
57
  end
57
58
 
58
59
  def params
60
+ if options[:models]
61
+ @index_mapping = {}
62
+ Array(options[:models]).each do |model|
63
+ @index_mapping[model.searchkick_index.name] = model
64
+ end
65
+ end
66
+
59
67
  index =
60
68
  if options[:index_name]
61
69
  Array(options[:index_name]).map { |v| v.respond_to?(:searchkick_index) ? v.searchkick_index.name : v }.join(",")
70
+ elsif options[:models]
71
+ @index_mapping.keys.join(",")
62
72
  elsif searchkick_index
63
73
  searchkick_index.name
64
74
  else
@@ -116,8 +126,8 @@ module Searchkick
116
126
  misspellings: @misspellings,
117
127
  term: term,
118
128
  scope_results: options[:scope_results],
119
- index_name: options[:index_name],
120
- total_entries: options[:total_entries]
129
+ total_entries: options[:total_entries],
130
+ index_mapping: @index_mapping
121
131
  }
122
132
 
123
133
  if options[:debug]
@@ -166,7 +176,7 @@ module Searchkick
166
176
  end
167
177
 
168
178
  def retry_misspellings?(response)
169
- @misspellings_below && response["hits"]["total"] < @misspellings_below
179
+ @misspellings_below && Searchkick::Results.new(searchkick_klass, response).total_count < @misspellings_below
170
180
  end
171
181
 
172
182
  private
@@ -377,7 +387,7 @@ module Searchkick
377
387
  queries_to_add.concat(q2)
378
388
  end
379
389
 
380
- queries.concat(queries_to_add)
390
+ queries << queries_to_add
381
391
 
382
392
  if options[:exclude]
383
393
  must_not.concat(set_exclude(exclude_field, exclude_analyzer))
@@ -392,9 +402,10 @@ module Searchkick
392
402
 
393
403
  should = []
394
404
  else
405
+ # higher score for matching more fields
395
406
  payload = {
396
- dis_max: {
397
- queries: queries
407
+ bool: {
408
+ should: queries.map { |qs| {dis_max: {queries: qs}} }
398
409
  }
399
410
  }
400
411
 
@@ -663,20 +674,9 @@ module Searchkick
663
674
  def set_boost_by_indices(payload)
664
675
  return unless options[:indices_boost]
665
676
 
666
- if below52?
667
- indices_boost = options[:indices_boost].each_with_object({}) do |(key, boost), memo|
668
- index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
669
- # try to use index explicitly instead of alias: https://github.com/elasticsearch/elasticsearch/issues/4756
670
- index_by_alias = Searchkick.client.indices.get_alias(index: index).keys.first
671
- memo[index_by_alias || index] = boost
672
- end
673
- else
674
- # array format supports alias resolution
675
- # https://github.com/elastic/elasticsearch/pull/21393
676
- indices_boost = options[:indices_boost].map do |key, boost|
677
- index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
678
- {index => boost}
679
- end
677
+ indices_boost = options[:indices_boost].map do |key, boost|
678
+ index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
679
+ {index => boost}
680
680
  end
681
681
 
682
682
  payload[:indices_boost] = indices_boost
@@ -713,7 +713,7 @@ module Searchkick
713
713
  def set_highlights(payload, fields)
714
714
  payload[:highlight] = {
715
715
  fields: Hash[fields.map { |f| [f, {}] }],
716
- fragment_size: below60? ? 30000 : 0
716
+ fragment_size: 0
717
717
  }
718
718
 
719
719
  if options[:highlight].is_a?(Hash)
@@ -824,7 +824,7 @@ module Searchkick
824
824
  # TODO id transformation for arrays
825
825
  def set_order(payload)
826
826
  order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc}
827
- id_field = below60? ? :_uid : :_id
827
+ id_field = :_id
828
828
  payload[:sort] = order.is_a?(Array) ? order : Hash[order.map { |k, v| [k.to_s == "id" ? id_field : k, v] }]
829
829
  end
830
830
 
@@ -1021,16 +1021,12 @@ module Searchkick
1021
1021
  k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "")
1022
1022
  end
1023
1023
 
1024
- def below52?
1025
- Searchkick.server_below?("5.2.0")
1026
- end
1027
-
1028
- def below60?
1029
- Searchkick.server_below?("6.0.0")
1030
- end
1031
-
1032
1024
  def below61?
1033
1025
  Searchkick.server_below?("6.1.0")
1034
1026
  end
1027
+
1028
+ def below70?
1029
+ Searchkick.server_below?("7.0.0")
1030
+ end
1035
1031
  end
1036
1032
  end
@@ -34,18 +34,13 @@ module Searchkick
34
34
  index.klass_document_type(record.class, ignore_type)
35
35
  end
36
36
 
37
- # memoize
38
- def self.routing_key
39
- @routing_key ||= Searchkick.server_below?("6.0.0") ? :_routing : :routing
40
- end
41
-
42
37
  def record_data
43
38
  data = {
44
39
  _index: index.name,
45
- _id: search_id,
46
- _type: document_type
40
+ _id: search_id
47
41
  }
48
- data[self.class.routing_key] = record.search_routing if record.respond_to?(:search_routing)
42
+ data[:_type] = document_type if Searchkick.server_below7?
43
+ data[:routing] = record.search_routing if record.respond_to?(:search_routing)
49
44
  data
50
45
  end
51
46
 
@@ -25,9 +25,16 @@ module Searchkick
25
25
  # results can have different types
26
26
  results = {}
27
27
 
28
- hits.group_by { |hit, _| hit["_type"] }.each do |type, grouped_hits|
29
- klass = (!options[:index_name] && @klass) || type.camelize.constantize
30
- results[type] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s }
28
+ hits.group_by { |hit, _| hit["_index"] }.each do |index, grouped_hits|
29
+ klass =
30
+ if @klass
31
+ @klass
32
+ else
33
+ index_alias = index.split("_")[0..-2].join("_")
34
+ (options[:index_mapping] || {})[index_alias]
35
+ end
36
+ raise Searchkick::Error, "Unknown model for index: #{index}" unless klass
37
+ results[index] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s }
31
38
  end
32
39
 
33
40
  missing_ids = []
@@ -35,7 +42,7 @@ module Searchkick
35
42
  # sort
36
43
  results =
37
44
  hits.map do |hit|
38
- result = results[hit["_type"]][hit["_id"].to_s]
45
+ result = results[hit["_index"]][hit["_id"].to_s]
39
46
  if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
40
47
  if (hit["highlight"] || options[:highlight]) && !result.respond_to?(:search_highlights)
41
48
  highlights = hit_highlights(hit)
@@ -132,7 +139,13 @@ module Searchkick
132
139
  end
133
140
 
134
141
  def total_count
135
- options[:total_entries] || response["hits"]["total"]
142
+ if options[:total_entries]
143
+ options[:total_entries]
144
+ elsif response["hits"]["total"].is_a?(Hash)
145
+ response["hits"]["total"]["value"]
146
+ else
147
+ response["hits"]["total"]
148
+ end
136
149
  end
137
150
  alias_method :total_entries, :total_count
138
151
 
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "3.1.3"
2
+ VERSION = "4.0.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.3
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: '5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: elasticsearch
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5'
33
+ version: '6'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5'
40
+ version: '6'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hashie
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -138,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
138
  requirements:
139
139
  - - ">="
140
140
  - !ruby/object:Gem::Version
141
- version: '2.2'
141
+ version: '2.4'
142
142
  required_rubygems_version: !ruby/object:Gem::Requirement
143
143
  requirements:
144
144
  - - ">="