rambling-trie 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/README.md +23 -7
  4. data/Rakefile +4 -0
  5. data/lib/rambling/trie.rb +27 -21
  6. data/lib/rambling/trie/comparable.rb +3 -3
  7. data/lib/rambling/trie/compressible.rb +14 -0
  8. data/lib/rambling/trie/compressor.rb +37 -24
  9. data/lib/rambling/trie/configuration/properties.rb +8 -6
  10. data/lib/rambling/trie/configuration/provider_collection.rb +34 -16
  11. data/lib/rambling/trie/container.rb +156 -36
  12. data/lib/rambling/trie/enumerable.rb +4 -4
  13. data/lib/rambling/trie/nodes.rb +11 -0
  14. data/lib/rambling/trie/nodes/compressed.rb +115 -0
  15. data/lib/rambling/trie/nodes/missing.rb +10 -0
  16. data/lib/rambling/trie/nodes/node.rb +151 -0
  17. data/lib/rambling/trie/nodes/raw.rb +89 -0
  18. data/lib/rambling/trie/readers/plain_text.rb +1 -11
  19. data/lib/rambling/trie/serializers/marshal.rb +4 -4
  20. data/lib/rambling/trie/serializers/yaml.rb +4 -4
  21. data/lib/rambling/trie/serializers/zip.rb +9 -8
  22. data/lib/rambling/trie/version.rb +1 -1
  23. data/spec/assets/test_words.es_DO.txt +1 -0
  24. data/spec/integration/rambling/trie_spec.rb +40 -35
  25. data/spec/lib/rambling/trie/comparable_spec.rb +6 -15
  26. data/spec/lib/rambling/trie/compressor_spec.rb +88 -13
  27. data/spec/lib/rambling/trie/configuration/properties_spec.rb +7 -7
  28. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +8 -20
  29. data/spec/lib/rambling/trie/container_spec.rb +159 -168
  30. data/spec/lib/rambling/trie/enumerable_spec.rb +12 -9
  31. data/spec/lib/rambling/trie/inspectable_spec.rb +11 -11
  32. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +35 -0
  33. data/spec/lib/rambling/trie/nodes/node_spec.rb +7 -0
  34. data/spec/lib/rambling/trie/nodes/raw_spec.rb +177 -0
  35. data/spec/lib/rambling/trie/serializers/file_spec.rb +4 -4
  36. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +3 -7
  37. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +3 -7
  38. data/spec/lib/rambling/trie/serializers/zip_spec.rb +16 -20
  39. data/spec/lib/rambling/trie/stringifyable_spec.rb +7 -8
  40. data/spec/lib/rambling/trie_spec.rb +2 -2
  41. data/spec/spec_helper.rb +3 -1
  42. data/spec/support/config.rb +4 -0
  43. data/spec/support/helpers/add_word.rb +18 -0
  44. data/spec/support/shared_examples/{a_compressable_trie.rb → a_compressible_trie.rb} +13 -3
  45. data/spec/support/shared_examples/a_serializable_trie.rb +8 -6
  46. data/spec/support/shared_examples/a_serializer.rb +6 -0
  47. data/spec/{lib/rambling/trie/node_spec.rb → support/shared_examples/a_trie_node.rb} +61 -30
  48. data/spec/{lib/rambling/trie/compressed_node_spec.rb → support/shared_examples/a_trie_node_implementation.rb} +18 -69
  49. metadata +22 -15
  50. data/lib/rambling/trie/compressable.rb +0 -14
  51. data/lib/rambling/trie/compressed_node.rb +0 -120
  52. data/lib/rambling/trie/missing_node.rb +0 -8
  53. data/lib/rambling/trie/node.rb +0 -97
  54. data/lib/rambling/trie/raw_node.rb +0 -96
  55. data/spec/lib/rambling/trie/raw_node_spec.rb +0 -389
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee20334126cebef1f6c2701fe7d612fde28854e3
4
- data.tar.gz: 832b58d0d0580d2318350adeafdd1b894b5f7ee4
3
+ metadata.gz: 63d9f2dee886a2a54a5e1df6316eff8abd21dc81
4
+ data.tar.gz: 5c25c7cfb39c458b6335d3e160cc543ecae2f951
5
5
  SHA512:
6
- metadata.gz: f2d654657d6cdaf376c84c28855c08ca4d9d21e752badf94e88a36f796dfeff0179abc748bd79cc6d7749b7840f9d0eeb20f7f62957237ec7c4861b016db61a2
7
- data.tar.gz: f46b5c920c9871e637706ce3a1a2578aca2e938c824979c5925ebf8f8994e7f5bbc85e1ac4b062da318db310c4642a9650d22fbbf8e516cc35967e9f1e3a7e89
6
+ metadata.gz: 798145e320bddef33321bf18fa2a7713c29e8cc82a004a83b257b71923a97df9a6610e73c08625e9c927f90a7833a2c9e7a800bb1b6c03aa61b7808dd893fc3e
7
+ data.tar.gz: 834c2e2fcc39611cda4d4de5847944bffac2bf5f6852d2c3ea12e3aca570f80ed9883666d7a35161cb1848712e2e7ecef21b05689c9d3e678a2afcea2f4f4592
data/Gemfile CHANGED
@@ -11,11 +11,12 @@ group :development do
11
11
  gem 'benchmark-ips'
12
12
  gem 'flamegraph'
13
13
  gem 'stackprof'
14
+ gem 'pry'
14
15
  end
15
16
 
16
17
  group :test do
17
18
  gem 'simplecov', require: false
18
- gem 'coveralls', require: false
19
+ gem 'coveralls', '~>0.8.21', require: false
19
20
  end
20
21
 
21
22
  group :local do
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rambling Trie
2
2
 
3
- [![Gem Version][badge_fury_badge]][badge_fury_link] [![Dependency Status][gemnasium_badge]][gemnasium_link] [![Build Status][travis_ci_badge]][travis_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link]
3
+ [![Gem Version][badge_fury_badge]][badge_fury_link] [![Dependency Status][gemnasium_badge]][gemnasium_link] [![Build Status][travis_ci_badge]][travis_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link]
4
4
 
5
5
  The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse.
6
6
 
@@ -10,7 +10,7 @@ The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wik
10
10
 
11
11
  You will need:
12
12
 
13
- * Ruby 2.1.0 or up
13
+ * Ruby 2.2.0 or up
14
14
  * RubyGems
15
15
 
16
16
  See [RVM][rvm], [rbenv][rbenv] or [chruby][chruby] for more information on how to manage Ruby versions.
@@ -75,6 +75,12 @@ trie.add 'word'
75
75
  trie << 'word'
76
76
  ```
77
77
 
78
+ Or if you have multiple words to add, you can use `#concat`:
79
+
80
+ ``` ruby
81
+ trie.concat %w(a collection of words)
82
+ ```
83
+
78
84
  And to find out if a word already exists in the trie, use `#word?` or its alias `#include?`:
79
85
 
80
86
  ``` ruby
@@ -121,13 +127,20 @@ trie.compress!
121
127
  This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child non-terminal nodes).
122
128
 
123
129
  > _**Note**: The `#compress!` method acts over the trie instance it belongs to
124
- > and is destructive. Also, adding words after compression (with `#add` or
130
+ > and replaces the root `Node`. Also, adding words after compression (with `#add` or
125
131
  > `#<<`) is not supported._
126
132
 
127
- You can find out if a trie instance is compressed by calling the `#compressed?` method:
133
+ If you want, you can also create a new compressed trie and leave the existing one intact. Just use `#compress` instead:
134
+
135
+ ``` ruby
136
+ compressed_trie = trie.compress
137
+ ```
138
+
139
+ You can find out if a trie instance is compressed by calling the `#compressed?` method. From the `#compress` example:
128
140
 
129
141
  ``` ruby
130
- trie.compressed?
142
+ trie.compressed? # => false
143
+ compressed_trie.compressed? # => true
131
144
  ```
132
145
 
133
146
  ### Enumeration
@@ -229,6 +242,7 @@ You can find further API documentation on the autogenerated [rambling-trie gem R
229
242
 
230
243
  The Rambling Trie has been tested with the following Ruby versions:
231
244
 
245
+ * 2.5.x
232
246
  * 2.4.x
233
247
  * 2.3.x
234
248
  * 2.2.x
@@ -268,7 +282,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
268
282
  [github_user_gonzedge]: https://github.com/gonzedge
269
283
  [inch_ci_badge]: https://inch-ci.org/github/gonzedge/rambling-trie.svg?branch=master
270
284
  [inch_ci_link]: https://inch-ci.org/github/gonzedge/rambling-trie
271
- [marshal]: https://ruby-doc.org/core-2.4.0/Marshal.html
285
+ [license_badge]: https://badges.frapsoft.com/os/mit/mit.svg?v=103
286
+ [license_link]: https://opensource.org/licenses/mit-license.php
287
+ [marshal]: https://ruby-doc.org/core-2.5.0/Marshal.html
272
288
  [rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration
273
289
  [rambling_trie_contributing_guide]: https://github.com/gonzedge/rambling-trie/blob/master/CONTRIBUTING.md
274
290
  [rambling_trie_plain_text_reader]: https://github.com/gonzedge/rambling-trie/blob/master/lib/rambling/trie/readers/plain_text.rb
@@ -280,4 +296,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
280
296
  [travis_ci_badge]: https://travis-ci.org/gonzedge/rambling-trie.svg
281
297
  [travis_ci_link]: https://travis-ci.org/gonzedge/rambling-trie
282
298
  [trie_wiki]: https://en.wikipedia.org/wiki/Trie
283
- [yaml]: https://ruby-doc.org/stdlib-2.4.0/libdoc/yaml/rdoc/YAML.html
299
+ [yaml]: https://ruby-doc.org/stdlib-2.5.0/libdoc/yaml/rdoc/YAML.html
data/Rakefile CHANGED
@@ -1,6 +1,10 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+
4
+ require 'rambling-trie'
3
5
  require_relative 'tasks/performance'
6
+ require_relative 'tasks/serialization'
7
+ require_relative 'tasks/ips'
4
8
 
5
9
  RSpec::Core::RakeTask.new :spec
6
10
 
data/lib/rambling/trie.rb CHANGED
@@ -1,9 +1,7 @@
1
- require 'forwardable'
2
-
3
1
  %w{
4
- comparable compressable compressor configuration container enumerable
5
- inspectable invalid_operation readers serializers stringifyable node
6
- missing_node compressed_node raw_node version
2
+ comparable compressible compressor configuration container enumerable
3
+ inspectable invalid_operation readers serializers stringifyable nodes
4
+ version
7
5
  }.each do |file|
8
6
  require File.join('rambling', 'trie', file)
9
7
  end
@@ -13,21 +11,12 @@ module Rambling
13
11
  # Entry point for rambling-trie API.
14
12
  module Trie
15
13
  class << self
16
- extend ::Forwardable
17
-
18
- delegate [
19
- :readers,
20
- :serializers,
21
- :compressor,
22
- :root_builder
23
- ] => :properties
24
-
25
14
  # Creates a new Rambling::Trie. Entry point for the Rambling::Trie API.
26
15
  # @param [String, nil] filepath the file to load the words from.
27
- # @param [Reader, nil] reader the file parser to get each word. See
28
- # {Rambling::Trie::Readers Readers}.
16
+ # @param [Reader, nil] reader the file parser to get each word.
29
17
  # @return [Container] the trie just created.
30
18
  # @yield [Container] the trie just created.
19
+ # @see Rambling::Trie::Readers Readers.
31
20
  def create filepath = nil, reader = nil
32
21
  Rambling::Trie::Container.new root_builder.call, compressor do |container|
33
22
  if filepath
@@ -44,9 +33,10 @@ module Rambling
44
33
  # Loads an existing trie from disk into memory.
45
34
  # @param [String] filepath the file to load the words from.
46
35
  # @param [Serializer, nil] serializer the object responsible of loading the trie
47
- # from disk. See {Rambling::Trie::Serializers Serializers}.
36
+ # from disk
48
37
  # @return [Container] the trie just loaded.
49
38
  # @yield [Container] the trie just loaded.
39
+ # @see Rambling::Trie::Serializers Serializers.
50
40
  def load filepath, serializer = nil
51
41
  serializer ||= serializers.resolve filepath
52
42
  root = serializer.load filepath
@@ -59,16 +49,16 @@ module Rambling
59
49
  # @param [Container] trie the trie to dump into disk.
60
50
  # @param [String] filepath the file to dump to serialized trie into.
61
51
  # @param [Serializer, nil] serializer the object responsible of
62
- # serializing and dumping the trie into disk. See
63
- # {Rambling::Trie::Serializers Serializers}.
52
+ # serializing and dumping the trie into disk.
53
+ # @see Rambling::Trie::Serializers Serializers.
64
54
  def dump trie, filepath, serializer = nil
65
55
  serializer ||= serializers.resolve filepath
66
56
  serializer.dump trie.root, filepath
67
57
  end
68
58
 
69
59
  # Provides configuration properties for the Rambling::Trie gem.
70
- # @return [Properties] the configured properties of the gem.
71
- # @yield [Properties] the configured properties of the gem.
60
+ # @return [Configuration::Properties] the configured properties of the gem.
61
+ # @yield [Configuration::Properties] the configured properties of the gem.
72
62
  def config
73
63
  yield properties if block_given?
74
64
  properties
@@ -79,6 +69,22 @@ module Rambling
79
69
  def properties
80
70
  @properties ||= Rambling::Trie::Configuration::Properties.new
81
71
  end
72
+
73
+ def readers
74
+ properties.readers
75
+ end
76
+
77
+ def serializers
78
+ properties.serializers
79
+ end
80
+
81
+ def compressor
82
+ properties.compressor
83
+ end
84
+
85
+ def root_builder
86
+ properties.root_builder
87
+ end
82
88
  end
83
89
  end
84
90
  end
@@ -3,9 +3,9 @@ module Rambling
3
3
  # Provides the comparable behavior for the trie data structure.
4
4
  module Comparable
5
5
  # Compares two nodes.
6
- # @param [Node] other the node to compare against.
7
- # @return [Boolean] `true` if the nodes' {Node#letter #letter} and
8
- # {Node#children_tree #children_tree} are equal, `false` otherwise.
6
+ # @param [Nodes::Node] other the node to compare against.
7
+ # @return [Boolean] `true` if the nodes' {Nodes::Node#letter #letter} and
8
+ # {Nodes::Node#children_tree #children_tree} are equal, `false` otherwise.
9
9
  def == other
10
10
  letter == other.letter &&
11
11
  terminal? == other.terminal? &&
@@ -0,0 +1,14 @@
1
+ module Rambling
2
+ module Trie
3
+ # Provides the compressible behavior for the trie data structure.
4
+ module Compressible
5
+ # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be compressed
6
+ # or not.
7
+ # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes with
8
+ # one child, `false` otherwise.
9
+ def compressible?
10
+ !(root? || terminal?) && children_tree.size == 1
11
+ end
12
+ end
13
+ end
14
+ end
@@ -2,47 +2,60 @@ module Rambling
2
2
  module Trie
3
3
  # Responsible for the compression process of a trie data structure.
4
4
  class Compressor
5
- # Compresses a {Node Node} from a trie data structure.
6
- # @param [RawNode] node the node to compress.
7
- # @return [CompressedNode] node the compressed version of the node.
5
+ # Compresses a {Nodes::Node Node} from a trie data structure.
6
+ # @param [Nodes::Raw] node the node to compress.
7
+ # @return [Nodes::Compressed] node the compressed version of the node.
8
8
  def compress node
9
- if node.compressable?
10
- merge_with_child_and_compress node
9
+ if node.compressible?
10
+ compress_child_and_merge node
11
11
  else
12
- copy_node_and_compress_children node
12
+ compress_children_and_copy node
13
13
  end
14
14
  end
15
15
 
16
16
  private
17
17
 
18
- def merge_with_child_and_compress node
19
- child = node.children.first
18
+ def compress_child_and_merge node
19
+ merge node, compress(node.first_child)
20
+ end
20
21
 
21
- letter = node.letter.to_s << child.letter.to_s
22
- new_node = new_compressed_node node, letter, child.terminal?
23
- new_node.children_tree = child.children_tree
22
+ def merge node, other
23
+ letter = node.letter.to_s << other.letter.to_s
24
24
 
25
- compress new_node
25
+ new_compressed_node(
26
+ letter.to_sym,
27
+ node.parent,
28
+ other.children_tree,
29
+ other.terminal?
30
+ )
26
31
  end
27
32
 
28
- def copy_node_and_compress_children node
29
- new_node = new_compressed_node node, node.letter, node.terminal?
33
+ def compress_children_and_copy node
34
+ new_compressed_node(
35
+ node.letter,
36
+ node.parent,
37
+ compress_children(node.children_tree),
38
+ node.terminal?
39
+ )
40
+ end
30
41
 
31
- node.children.each do |child|
32
- compressed_child = compress child
42
+ def compress_children children_tree
43
+ new_children_tree = {}
33
44
 
34
- compressed_child.parent = new_node
35
- new_node[compressed_child.letter] = compressed_child
45
+ children_tree.each_value do |child|
46
+ compressed_child = compress child
47
+ new_children_tree[compressed_child.letter] = compressed_child
36
48
  end
37
49
 
38
- new_node
50
+ new_children_tree
39
51
  end
40
52
 
41
- def new_compressed_node node, letter, terminal
42
- new_node = Rambling::Trie::CompressedNode.new node.parent
43
- new_node.letter = letter
44
- new_node.terminal! if terminal
45
- new_node
53
+ def new_compressed_node letter, parent, children_tree, terminal
54
+ node = Rambling::Trie::Nodes::Compressed.new letter, parent, children_tree
55
+ node.terminal! if terminal
56
+
57
+ children_tree.each_value { |child| child.parent = node }
58
+ node
46
59
  end
47
60
  end
48
61
  end
@@ -17,11 +17,13 @@ module Rambling
17
17
  # @return [Compressor] the configured compressor.
18
18
  attr_accessor :compressor
19
19
 
20
- # The configured root_builder, which should return a {Node Node} when
21
- # called.
22
- # @return [Proc<Node>] the configured root_builder.
20
+ # The configured root_builder, which should return a {Nodes::Node Node} when
21
+ # called.
22
+ # @return [Proc<Nodes::Node>] the configured root_builder.
23
23
  attr_accessor :root_builder
24
24
 
25
+ # The configured tmp_path, which will be used for throwaway files.
26
+ # @return [String] the configured tmp_path.
25
27
  attr_accessor :tmp_path
26
28
 
27
29
  # Returns a new properties instance.
@@ -35,7 +37,7 @@ module Rambling
35
37
  reset_serializers
36
38
 
37
39
  self.compressor = Rambling::Trie::Compressor.new
38
- self.root_builder = lambda { Rambling::Trie::RawNode.new }
40
+ self.root_builder = lambda { Rambling::Trie::Nodes::Raw.new }
39
41
  self.tmp_path = '/tmp'
40
42
  end
41
43
 
@@ -46,7 +48,7 @@ module Rambling
46
48
  def reset_readers
47
49
  plain_text_reader = Rambling::Trie::Readers::PlainText.new
48
50
 
49
- self.readers = Rambling::Trie::Configuration::ProviderCollection.new 'reader', txt: plain_text_reader
51
+ self.readers = Rambling::Trie::Configuration::ProviderCollection.new :reader, txt: plain_text_reader
50
52
  end
51
53
 
52
54
  def reset_serializers
@@ -54,7 +56,7 @@ module Rambling
54
56
  yaml_serializer = Rambling::Trie::Serializers::Yaml.new
55
57
  zip_serializer = Rambling::Trie::Serializers::Zip.new self
56
58
 
57
- self.serializers = Rambling::Trie::Configuration::ProviderCollection.new 'serializer',
59
+ self.serializers = Rambling::Trie::Configuration::ProviderCollection.new :serializer,
58
60
  marshal: marshal_serializer,
59
61
  yml: yaml_serializer,
60
62
  yaml: yaml_serializer,
@@ -3,8 +3,6 @@ module Rambling
3
3
  module Configuration
4
4
  # Collection of configurable providers.
5
5
  class ProviderCollection
6
- extend ::Forwardable
7
-
8
6
  # The name of this provider collection.
9
7
  # @return [String] the name of this provider collection.
10
8
  attr_reader :name
@@ -23,13 +21,6 @@ module Rambling
23
21
  # cannot be resolved in {ProviderCollection#resolve #resolve}.
24
22
  attr_reader :default
25
23
 
26
- delegate [
27
- :[],
28
- :[]=,
29
- :keys,
30
- :values,
31
- ] => :providers
32
-
33
24
  # Creates a new provider collection.
34
25
  # @param [String] name the name for this provider collection.
35
26
  # @param [Hash] providers the configured providers.
@@ -52,7 +43,7 @@ module Rambling
52
43
  end
53
44
 
54
45
  def default= provider
55
- if provider_not_in_list? provider
46
+ unless contains? provider
56
47
  raise ArgumentError, "default #{name} should be part of configured #{name}s"
57
48
  end
58
49
 
@@ -71,30 +62,57 @@ module Rambling
71
62
  # @return [Object] the provider corresponding to the file extension in
72
63
  # this provider collection. {#default} if not found.
73
64
  def resolve filepath
74
- providers[format filepath] || default
65
+ providers[file_format filepath] || default
75
66
  end
76
67
 
77
68
  # Resets the provider collection to the initial values.
78
69
  def reset
79
70
  providers.clear
80
- configured_providers.each { |k, v| providers[k] = v }
71
+ configured_providers.each { |k, v| self[k] = v }
81
72
  self.default = configured_default
82
73
  end
83
74
 
75
+ # Get provider corresponding to a given format.
76
+ # @return [Array<Symbol>] the provider corresponding to that format.
77
+ # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D
78
+ # Hash#keys
79
+ def formats
80
+ providers.keys
81
+ end
82
+
83
+ # Get provider corresponding to a given format.
84
+ # @param [Symbol] format the format to search for in the collection.
85
+ # @return [Object] the provider corresponding to that format.
86
+ # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D
87
+ # Hash#[]
88
+ def [] format
89
+ providers[format]
90
+ end
91
+
84
92
  private
85
93
 
86
94
  attr_reader :configured_providers, :configured_default
87
95
 
88
- def format filepath
96
+ def []= format, instance
97
+ providers[format] = instance
98
+ end
99
+
100
+ def values
101
+ providers.values
102
+ end
103
+
104
+ def file_format filepath
89
105
  format = File.extname filepath
90
106
  format.slice! 0
91
107
  format.to_sym
92
108
  end
93
109
 
94
- def provider_not_in_list? provider
95
- (provider && providers.values.empty?) ||
96
- (providers.values.any? && !providers.values.include?(provider))
110
+ def contains? provider
111
+ provider.nil? ||
112
+ (providers.any? && provider_instances.include?(provider))
97
113
  end
114
+
115
+ alias_method :provider_instances, :values
98
116
  end
99
117
  end
100
118
  end