chefspec 9.1.0 → 9.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +16 -9
  3. data/Rakefile +60 -52
  4. data/chefspec.gemspec +20 -20
  5. data/lib/chefspec/api/core.rb +3 -3
  6. data/lib/chefspec/api/described.rb +3 -5
  7. data/lib/chefspec/api/stubs.rb +2 -2
  8. data/lib/chefspec/api/stubs_for.rb +22 -19
  9. data/lib/chefspec/api.rb +14 -14
  10. data/lib/chefspec/berkshelf.rb +4 -4
  11. data/lib/chefspec/cacher.rb +2 -2
  12. data/lib/chefspec/coverage/filters.rb +18 -15
  13. data/lib/chefspec/coverage.rb +35 -40
  14. data/lib/chefspec/deprecations.rb +3 -3
  15. data/lib/chefspec/errors.rb +7 -7
  16. data/lib/chefspec/expect_exception.rb +2 -1
  17. data/lib/chefspec/extensions/chef/client.rb +3 -3
  18. data/lib/chefspec/extensions/chef/conditional.rb +2 -1
  19. data/lib/chefspec/extensions/chef/cookbook/gem_installer.rb +5 -4
  20. data/lib/chefspec/extensions/chef/cookbook_loader.rb +1 -0
  21. data/lib/chefspec/extensions/chef/cookbook_uploader.rb +1 -1
  22. data/lib/chefspec/extensions/chef/data_query.rb +3 -3
  23. data/lib/chefspec/extensions/chef/lwrp_base.rb +1 -0
  24. data/lib/chefspec/extensions/chef/provider.rb +8 -5
  25. data/lib/chefspec/extensions/chef/resource/freebsd_package.rb +2 -1
  26. data/lib/chefspec/extensions/chef/resource.rb +18 -12
  27. data/lib/chefspec/extensions/chef/run_context/cookbook_compiler.rb +21 -1
  28. data/lib/chefspec/extensions/chef/securable.rb +1 -1
  29. data/lib/chefspec/extensions/ohai/system.rb +11 -0
  30. data/lib/chefspec/extensions.rb +14 -13
  31. data/lib/chefspec/file_cache_path_proxy.rb +3 -3
  32. data/lib/chefspec/formatter.rb +15 -3
  33. data/lib/chefspec/librarian.rb +7 -6
  34. data/lib/chefspec/matchers/do_nothing_matcher.rb +15 -15
  35. data/lib/chefspec/matchers/include_any_recipe_matcher.rb +4 -4
  36. data/lib/chefspec/matchers/include_recipe_matcher.rb +1 -1
  37. data/lib/chefspec/matchers/link_to_matcher.rb +2 -2
  38. data/lib/chefspec/matchers/notifications_matcher.rb +5 -4
  39. data/lib/chefspec/matchers/render_file_matcher.rb +3 -3
  40. data/lib/chefspec/matchers/resource_matcher.rb +18 -16
  41. data/lib/chefspec/matchers.rb +9 -9
  42. data/lib/chefspec/mixins/normalize.rb +1 -1
  43. data/lib/chefspec/policyfile.rb +6 -6
  44. data/lib/chefspec/renderer.rb +4 -4
  45. data/lib/chefspec/rspec.rb +1 -1
  46. data/lib/chefspec/server.rb +1 -1
  47. data/lib/chefspec/server_methods.rb +8 -8
  48. data/lib/chefspec/server_runner.rb +10 -10
  49. data/lib/chefspec/solo_runner.rb +27 -25
  50. data/lib/chefspec/stubs/command_registry.rb +1 -1
  51. data/lib/chefspec/stubs/command_stub.rb +1 -1
  52. data/lib/chefspec/stubs/data_bag_item_registry.rb +1 -1
  53. data/lib/chefspec/stubs/data_bag_item_stub.rb +1 -1
  54. data/lib/chefspec/stubs/data_bag_registry.rb +1 -1
  55. data/lib/chefspec/stubs/data_bag_stub.rb +1 -1
  56. data/lib/chefspec/stubs/registry.rb +1 -1
  57. data/lib/chefspec/stubs/search_registry.rb +2 -2
  58. data/lib/chefspec/stubs/search_stub.rb +2 -2
  59. data/lib/chefspec/util.rb +7 -7
  60. data/lib/chefspec/version.rb +1 -1
  61. data/lib/chefspec/zero_server.rb +4 -4
  62. data/lib/chefspec.rb +29 -29
  63. data/spec/spec_helper.rb +3 -4
  64. data/spec/support/hash.rb +3 -3
  65. data/spec/unit/cacher_spec.rb +17 -17
  66. data/spec/unit/coverage/filters_spec.rb +16 -16
  67. data/spec/unit/deprecations_spec.rb +8 -9
  68. data/spec/unit/errors_spec.rb +15 -15
  69. data/spec/unit/expect_exception_spec.rb +9 -9
  70. data/spec/unit/macros_spec.rb +50 -50
  71. data/spec/unit/matchers/do_nothing_matcher.rb +1 -1
  72. data/spec/unit/matchers/include_any_recipe_matcher_spec.rb +23 -23
  73. data/spec/unit/matchers/include_recipe_matcher_spec.rb +15 -15
  74. data/spec/unit/matchers/link_to_matcher_spec.rb +18 -18
  75. data/spec/unit/matchers/notifications_matcher_spec.rb +15 -16
  76. data/spec/unit/matchers/render_file_matcher_spec.rb +26 -26
  77. data/spec/unit/matchers/resource_matcher_spec.rb +1 -1
  78. data/spec/unit/matchers/state_attrs_matcher_spec.rb +24 -24
  79. data/spec/unit/matchers/subscribes_matcher_spec.rb +27 -29
  80. data/spec/unit/renderer_spec.rb +36 -36
  81. data/spec/unit/server_runner_spec.rb +6 -6
  82. data/spec/unit/solo_runner_spec.rb +69 -69
  83. data/spec/unit/stubs/command_registry_spec.rb +11 -11
  84. data/spec/unit/stubs/command_stub_spec.rb +26 -26
  85. data/spec/unit/stubs/data_bag_item_registry_spec.rb +17 -17
  86. data/spec/unit/stubs/data_bag_item_stub_spec.rb +14 -14
  87. data/spec/unit/stubs/data_bag_registry_spec.rb +16 -16
  88. data/spec/unit/stubs/data_bag_stub_spec.rb +13 -13
  89. data/spec/unit/stubs/registry_spec.rb +9 -9
  90. data/spec/unit/stubs/search_registry_spec.rb +17 -17
  91. data/spec/unit/stubs/search_stub_spec.rb +14 -14
  92. data/spec/unit/stubs/stub_spec.rb +22 -22
  93. metadata +10 -11
  94. data/lib/chefspec/extensions/.DS_Store +0 -0
  95. data/lib/chefspec/extensions/chef/.DS_Store +0 -0
@@ -1,13 +1,13 @@
1
1
  module ChefSpec
2
2
  module Matchers
3
- require_relative 'matchers/do_nothing_matcher'
4
- require_relative 'matchers/include_any_recipe_matcher'
5
- require_relative 'matchers/include_recipe_matcher'
6
- require_relative 'matchers/link_to_matcher'
7
- require_relative 'matchers/notifications_matcher'
8
- require_relative 'matchers/render_file_matcher'
9
- require_relative 'matchers/resource_matcher'
10
- require_relative 'matchers/state_attrs_matcher'
11
- require_relative 'matchers/subscribes_matcher'
3
+ require_relative "matchers/do_nothing_matcher"
4
+ require_relative "matchers/include_any_recipe_matcher"
5
+ require_relative "matchers/include_recipe_matcher"
6
+ require_relative "matchers/link_to_matcher"
7
+ require_relative "matchers/notifications_matcher"
8
+ require_relative "matchers/render_file_matcher"
9
+ require_relative "matchers/resource_matcher"
10
+ require_relative "matchers/state_attrs_matcher"
11
+ require_relative "matchers/subscribes_matcher"
12
12
  end
13
13
  end
@@ -16,7 +16,7 @@ module ChefSpec
16
16
  else
17
17
  name = thing
18
18
  end
19
- name.to_s.gsub('-', '_').to_sym
19
+ name.to_s.gsub("-", "_").to_sym
20
20
  end
21
21
  end
22
22
  end
@@ -1,8 +1,8 @@
1
1
  begin
2
- require 'chef-cli/policyfile_services/export_repo'
3
- require 'chef-cli/policyfile_services/install'
2
+ require "chef-cli/policyfile_services/export_repo"
3
+ require "chef-cli/policyfile_services/install"
4
4
  rescue LoadError
5
- raise ChefSpec::Error::GemLoadError.new(gem: 'chef-cli', name: 'ChefCLI')
5
+ raise ChefSpec::Error::GemLoadError.new(gem: "chef-cli", name: "ChefCLI")
6
6
  end
7
7
 
8
8
  module ChefSpec
@@ -24,7 +24,7 @@ module ChefSpec
24
24
  def setup!
25
25
  policyfile_path = RSpec.configuration.policyfile_path
26
26
  if policyfile_path.nil?
27
- policyfile_path = File.join(Dir.pwd, 'Policyfile.rb')
27
+ policyfile_path = File.join(Dir.pwd, "Policyfile.rb")
28
28
  end
29
29
 
30
30
  installer = ChefCLI::PolicyfileServices::Install.new(
@@ -44,8 +44,8 @@ module ChefSpec
44
44
 
45
45
  ::RSpec.configure do |config|
46
46
  config.cookbook_path = [
47
- File.join(@tmpdir, 'cookbooks'),
48
- File.join(@tmpdir, 'cookbook_artifacts')
47
+ File.join(@tmpdir, "cookbooks"),
48
+ File.join(@tmpdir, "cookbook_artifacts"),
49
49
  ]
50
50
  end
51
51
  end
@@ -1,6 +1,6 @@
1
1
  begin
2
- require 'chef/mixin/template'
3
- require 'chef/provider/template_finder'
2
+ require "chef/mixin/template"
3
+ require "chef/provider/template_finder"
4
4
  rescue LoadError
5
5
  end
6
6
 
@@ -67,8 +67,8 @@ module ChefSpec
67
67
  if Chef::Mixin::Template.const_defined?(:TemplateContext) # Chef 11+
68
68
  template_context = Chef::Mixin::Template::TemplateContext.new([])
69
69
  template_context.update({
70
- :node => chef_run.node,
71
- :template_finder => template_finder(chef_run, cookbook_name),
70
+ node: chef_run.node,
71
+ template_finder: template_finder(chef_run, cookbook_name),
72
72
  }.merge(template.variables))
73
73
  if template.respond_to?(:helper_modules) # Chef 11.4+
74
74
  template_context._extend_modules(template.helper_modules)
@@ -1,5 +1,5 @@
1
1
  RSpec.configure do |config|
2
- unless ENV['CHEFSPEC_NO_INCLUDE']
2
+ unless ENV["CHEFSPEC_NO_INCLUDE"]
3
3
  config.include(ChefSpec::API)
4
4
  end
5
5
 
@@ -1,4 +1,4 @@
1
1
  # @todo Remove in v5.0.0
2
- require_relative 'deprecations'
2
+ require_relative "deprecations"
3
3
  deprecated "require 'chefspec/server' is no longer required and " \
4
4
  "will be removed in the next major release."
@@ -88,11 +88,11 @@ module ChefSpec
88
88
  EOH
89
89
  end
90
90
 
91
- entity :client, Chef::Client, 'clients'
92
- entity :data_bag, Chef::DataBag, 'data'
93
- entity :environment, Chef::Environment, 'environments'
94
- entity :node, Chef::Node, 'nodes'
95
- entity :role, Chef::Role, 'roles'
91
+ entity :client, Chef::Client, "clients"
92
+ entity :data_bag, Chef::DataBag, "data"
93
+ entity :environment, Chef::Environment, "environments"
94
+ entity :node, Chef::Node, "nodes"
95
+ entity :role, Chef::Role, "roles"
96
96
 
97
97
  #
98
98
  # Create a new data_bag on the Chef Server. This overrides the method
@@ -104,7 +104,7 @@ module ChefSpec
104
104
  # the data to load into the data bag
105
105
  #
106
106
  def create_data_bag(name, data = {})
107
- load_data(name, 'data', data)
107
+ load_data(name, "data", data)
108
108
  end
109
109
 
110
110
  #
@@ -138,7 +138,7 @@ module ChefSpec
138
138
  data = JSON.fast_generate(data)
139
139
  end
140
140
 
141
- load_data(name, 'nodes', data)
141
+ load_data(name, "nodes", data)
142
142
  end
143
143
  alias_method :update_node, :create_node
144
144
 
@@ -161,7 +161,7 @@ module ChefSpec
161
161
  # Get the path to an item in the data store.
162
162
  #
163
163
  def get(*args)
164
- args.unshift('organizations', 'chef')
164
+ args.unshift("organizations", "chef")
165
165
 
166
166
  if args.size == 3
167
167
  server.data_store.list(args)
@@ -1,10 +1,10 @@
1
- require 'chef/cookbook_loader'
2
- require 'chef/cookbook_uploader'
1
+ require "chef/cookbook_loader"
2
+ require "chef/cookbook_uploader"
3
3
 
4
- require_relative 'zero_server'
5
- require_relative 'file_cache_path_proxy'
6
- require_relative 'server_methods'
7
- require_relative 'solo_runner'
4
+ require_relative "zero_server"
5
+ require_relative "file_cache_path_proxy"
6
+ require_relative "server_methods"
7
+ require_relative "solo_runner"
8
8
 
9
9
  module ChefSpec
10
10
  class ServerRunner < SoloRunner
@@ -54,8 +54,8 @@ module ChefSpec
54
54
  #
55
55
  def client_key
56
56
  tmp = Dir.mktmpdir
57
- path = File.join(tmp, 'client.pem')
58
- File.open(path, 'wb') { |f| f.write(ChefZero::PRIVATE_KEY) }
57
+ path = File.join(tmp, "client.pem")
58
+ File.open(path, "wb") { |f| f.write(ChefZero::PRIVATE_KEY) }
59
59
  at_exit { FileUtils.rm_rf(tmp) }
60
60
  path
61
61
  end
@@ -64,8 +64,8 @@ module ChefSpec
64
64
  def apply_chef_config!
65
65
  super
66
66
  Chef::Config[:client_key] = client_key
67
- Chef::Config[:client_name] = 'chefspec'
68
- Chef::Config[:node_name] = 'chefspec'
67
+ Chef::Config[:client_name] = "chefspec"
68
+ Chef::Config[:node_name] = "chefspec"
69
69
  Chef::Config[:solo] = false
70
70
  Chef::Config[:solo_legacy_mode] = false
71
71
 
@@ -1,9 +1,9 @@
1
- require 'fauxhai'
2
- require 'chef/client'
3
- require 'chef/cookbook/metadata'
4
- require 'chef/mash'
5
- require 'chef/providers'
6
- require 'chef/resources'
1
+ require "fauxhai"
2
+ require "chef/client"
3
+ require "chef/cookbook/metadata"
4
+ require "chef/mash"
5
+ require "chef/providers"
6
+ require "chef/resources"
7
7
 
8
8
  module ChefSpec
9
9
  class SoloRunner
@@ -123,6 +123,7 @@ module ChefSpec
123
123
  if converge_val.is_a?(Exception)
124
124
  raise converge_val
125
125
  end
126
+
126
127
  self
127
128
  end
128
129
 
@@ -136,7 +137,7 @@ module ChefSpec
136
137
  #
137
138
  def converge_block(&block)
138
139
  converge do
139
- recipe = Chef::Recipe.new(cookbook_name, '_test', run_context)
140
+ recipe = Chef::Recipe.new(cookbook_name, "_test", run_context)
140
141
  recipe.instance_exec(&block)
141
142
  end
142
143
  end
@@ -149,7 +150,8 @@ module ChefSpec
149
150
  #
150
151
  def preload!
151
152
  # Flag to disable preloading for situations where it doesn't make sense.
152
- return if ENV['CHEFSPEC_NO_PRELOAD']
153
+ return if ENV["CHEFSPEC_NO_PRELOAD"]
154
+
153
155
  begin
154
156
  old_preload = $CHEFSPEC_PRELOAD
155
157
  $CHEFSPEC_PRELOAD = true
@@ -206,7 +208,7 @@ module ChefSpec
206
208
  #
207
209
  def find_resource(type, name, action = nil)
208
210
  resource_collection.all_resources.reverse_each.find do |resource|
209
- resource.declared_type == type.to_sym && (name === resource.identity || name === resource.name) && (action.nil? || resource.performed_action?(action))
211
+ resource.declared_type == type.to_sym && (name === resource.name || name === resource.identity) && (action.nil? || resource.performed_action?(action))
210
212
  end
211
213
  end
212
214
 
@@ -292,7 +294,8 @@ module ChefSpec
292
294
  # Respond to custom matchers defined by the user.
293
295
  #
294
296
  def method_missing(m, *args, &block)
295
- if block = ChefSpec.matchers[resource_name(m.to_sym)]
297
+ block = ChefSpec.matchers[resource_name(m.to_sym)]
298
+ if block
296
299
  instance_exec(args.first, &block)
297
300
  else
298
301
  super
@@ -358,11 +361,11 @@ module ChefSpec
358
361
  # @return [String]
359
362
  #
360
363
  def calling_cookbook_root(options, kaller)
361
- calling_spec = options[:spec_declaration_locations] || kaller.find { |line| line =~ /\/spec/ }
364
+ calling_spec = options[:spec_declaration_locations] || kaller.find { |line| line =~ %r{/spec} }
362
365
  raise Error::CookbookPathNotFound if calling_spec.nil?
363
366
 
364
367
  bits = calling_spec.split(/:[0-9]/, 2).first.split(File::SEPARATOR)
365
- spec_dir = bits.index('spec') || 0
368
+ spec_dir = bits.index("spec") || 0
366
369
 
367
370
  File.join(bits.slice(0, spec_dir))
368
371
  end
@@ -378,7 +381,7 @@ module ChefSpec
378
381
  # @return [String]
379
382
  #
380
383
  def calling_cookbook_path(options, kaller)
381
- File.expand_path(File.join(calling_cookbook_root(options, kaller), '..'))
384
+ File.expand_path(File.join(calling_cookbook_root(options, kaller), ".."))
382
385
  end
383
386
 
384
387
  #
@@ -388,7 +391,7 @@ module ChefSpec
388
391
  #
389
392
  def default_role_path
390
393
  Pathname.new(Dir.pwd).ascend do |path|
391
- possible = File.join(path, 'roles')
394
+ possible = File.join(path, "roles")
392
395
  return possible if File.exist?(possible)
393
396
  end
394
397
 
@@ -402,7 +405,7 @@ module ChefSpec
402
405
  #
403
406
  def default_environment_path
404
407
  Pathname.new(Dir.pwd).ascend do |path|
405
- possible = File.join(path, 'environments')
408
+ possible = File.join(path, "environments")
406
409
  return possible if File.exist?(possible)
407
410
  end
408
411
 
@@ -459,7 +462,7 @@ module ChefSpec
459
462
  # @return [Chef::Cookbook::Metadata]
460
463
  #
461
464
  def cookbook
462
- @cookbook ||= Chef::Cookbook::Metadata.new.tap {|m| m.from_file("#{options[:cookbook_root]}/metadata.rb") }
465
+ @cookbook ||= Chef::Cookbook::Metadata.new.tap { |m| m.from_file("#{options[:cookbook_root]}/metadata.rb") }
463
466
  end
464
467
 
465
468
  #
@@ -470,12 +473,11 @@ module ChefSpec
470
473
  def cookbook_name
471
474
  # Try to figure out the name of this cookbook, pretending this block
472
475
  # is in the name context as the cookbook under test.
473
- begin
474
- cookbook.name
475
- rescue IOError
476
- # Old cookbook, has no metadata, use the folder name I guess.
477
- File.basename(options[:cookbook_root])
478
- end
476
+
477
+ cookbook.name
478
+ rescue IOError
479
+ # Old cookbook, has no metadata, use the folder name I guess.
480
+ File.basename(options[:cookbook_root])
479
481
  end
480
482
 
481
483
  #
@@ -489,8 +491,8 @@ module ChefSpec
489
491
 
490
492
  Chef::Config.reset!
491
493
  Chef::Config.formatters.clear
492
- Chef::Config.add_formatter('chefspec')
493
- Chef::Config[:cache_type] = 'Memory'
494
+ Chef::Config.add_formatter("chefspec")
495
+ Chef::Config[:cache_type] = "Memory"
494
496
  Chef::Config[:client_key] = nil
495
497
  Chef::Config[:client_name] = nil
496
498
  Chef::Config[:node_name] = nil
@@ -506,7 +508,7 @@ module ChefSpec
506
508
  Chef::Config[:force_logger] = true
507
509
  Chef::Config[:solo] = true
508
510
  Chef::Config[:solo_legacy_mode] = true
509
- Chef::Config[:use_policyfile] = false
511
+ Chef::Config[:use_policyfile] = false
510
512
  Chef::Config[:environment_path] = @options[:environment_path]
511
513
  end
512
514
 
@@ -1,4 +1,4 @@
1
- require_relative 'registry'
1
+ require_relative "registry"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -1,4 +1,4 @@
1
- require_relative 'stub'
1
+ require_relative "stub"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -1,4 +1,4 @@
1
- require_relative 'registry'
1
+ require_relative "registry"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -1,4 +1,4 @@
1
- require_relative 'stub'
1
+ require_relative "stub"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -1,4 +1,4 @@
1
- require_relative 'registry'
1
+ require_relative "registry"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -1,4 +1,4 @@
1
- require_relative 'stub'
1
+ require_relative "stub"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -25,7 +25,7 @@ module ChefSpec
25
25
  end
26
26
 
27
27
  def stub_for(*args)
28
- raise ArgumentError, '#stub_for is an abstract function'
28
+ raise ArgumentError, "#stub_for is an abstract function"
29
29
  end
30
30
  end
31
31
  end
@@ -1,9 +1,9 @@
1
- require_relative 'registry'
1
+ require_relative "registry"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
5
5
  class SearchRegistry < Registry
6
- def stub_for(type, query = '*:*')
6
+ def stub_for(type, query = "*:*")
7
7
  @stubs.find do |stub|
8
8
  stub.type.to_s == type.to_s && stub.query === query
9
9
  end
@@ -1,4 +1,4 @@
1
- require_relative 'stub'
1
+ require_relative "stub"
2
2
 
3
3
  module ChefSpec
4
4
  module Stubs
@@ -7,7 +7,7 @@ module ChefSpec
7
7
  attr_reader :query
8
8
  attr_reader :type
9
9
 
10
- def initialize(type, query = '*:*', &block)
10
+ def initialize(type, query = "*:*", &block)
11
11
  @type = type.to_s
12
12
  @query = query
13
13
  @block = block
data/lib/chefspec/util.rb CHANGED
@@ -14,10 +14,10 @@ module ChefSpec
14
14
  def underscore(string)
15
15
  string
16
16
  .to_s
17
- .gsub(/::/, '/')
18
- .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
19
- .gsub(/([a-z\d])([A-Z])/,'\1_\2')
20
- .tr('-', '_')
17
+ .gsub(/::/, "/")
18
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
19
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
20
+ .tr("-", "_")
21
21
  .downcase
22
22
  end
23
23
 
@@ -32,8 +32,8 @@ module ChefSpec
32
32
  def camelize(string)
33
33
  string
34
34
  .to_s
35
- .split('_')
36
- .map { |e| e.capitalize }
35
+ .split("_")
36
+ .map(&:capitalize)
37
37
  .join
38
38
  end
39
39
 
@@ -49,7 +49,7 @@ module ChefSpec
49
49
  length = options[:length] || 30
50
50
 
51
51
  if string.length > length
52
- string[0..length-3] + '...'
52
+ string[0..length - 3] + "..."
53
53
  else
54
54
  string
55
55
  end
@@ -1,3 +1,3 @@
1
1
  module ChefSpec
2
- VERSION = '9.1.0'
2
+ VERSION = "9.3.1".freeze
3
3
  end