fog-core 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +2 -0
  3. data/.github/workflows/ruby.yml +1 -1
  4. data/.github/workflows/stale.yml +1 -1
  5. data/.rubocop.yml +16 -12
  6. data/.rubocop_todo.yml +724 -0
  7. data/Gemfile +1 -1
  8. data/Rakefile +2 -14
  9. data/changelog.md +14 -0
  10. data/fog-core.gemspec +10 -7
  11. data/lib/fog/compute/models/server.rb +7 -3
  12. data/lib/fog/compute.rb +2 -2
  13. data/lib/fog/core/association.rb +1 -0
  14. data/lib/fog/core/attributes/default.rb +7 -0
  15. data/lib/fog/core/attributes.rb +28 -3
  16. data/lib/fog/core/cache.rb +58 -55
  17. data/lib/fog/core/collection.rb +9 -3
  18. data/lib/fog/core/connection.rb +1 -1
  19. data/lib/fog/core/current_machine.rb +1 -1
  20. data/lib/fog/core/errors.rb +1 -1
  21. data/lib/fog/core/logger.rb +2 -2
  22. data/lib/fog/core/mock.rb +6 -1
  23. data/lib/fog/core/model.rb +34 -5
  24. data/lib/fog/core/provider.rb +7 -7
  25. data/lib/fog/core/scp.rb +15 -11
  26. data/lib/fog/core/service.rb +4 -4
  27. data/lib/fog/core/services_mixin.rb +9 -9
  28. data/lib/fog/core/ssh.rb +3 -2
  29. data/lib/fog/core/stringify_keys.rb +0 -2
  30. data/lib/fog/core/time.rb +2 -2
  31. data/lib/fog/core/uuid.rb +2 -8
  32. data/lib/fog/core/version.rb +1 -1
  33. data/lib/fog/core/wait_for.rb +2 -1
  34. data/lib/fog/core/wait_for_defaults.rb +2 -0
  35. data/lib/fog/core.rb +57 -58
  36. data/lib/fog/formatador.rb +7 -6
  37. data/lib/fog/schema/data_validator.rb +1 -0
  38. data/lib/fog/storage.rb +15 -15
  39. data/lib/fog/test_helpers/collection_helper.rb +2 -0
  40. data/lib/fog/test_helpers/formats_helper.rb +2 -2
  41. data/lib/fog/test_helpers/helper.rb +3 -3
  42. data/lib/fog/test_helpers/minitest/assertions.rb +1 -1
  43. data/lib/fog/test_helpers/minitest/expectations.rb +1 -1
  44. data/lib/fog/test_helpers/mock_helper.rb +84 -84
  45. data/lib/fog/test_helpers/types_helper.rb +1 -0
  46. data/lib/tasks/test_task.rb +2 -2
  47. data/spec/compute/models/server_spec.rb +7 -7
  48. data/spec/compute_spec.rb +6 -6
  49. data/spec/connection_spec.rb +11 -9
  50. data/spec/core/cache_spec.rb +51 -15
  51. data/spec/core/collection_spec.rb +24 -0
  52. data/spec/core/model_spec.rb +36 -3
  53. data/spec/core/stringify_keys_spec.rb +3 -3
  54. data/spec/core/whitelist_keys_spec.rb +2 -2
  55. data/spec/current_machine_spec.rb +2 -2
  56. data/spec/fog_attribute_spec.rb +183 -163
  57. data/spec/formatador_spec.rb +7 -7
  58. data/spec/identity_spec.rb +6 -6
  59. data/spec/mocking_spec.rb +3 -3
  60. data/spec/service_spec.rb +19 -19
  61. data/spec/spec_helper.rb +3 -8
  62. data/spec/storage_spec.rb +6 -6
  63. data/spec/test_helpers/formats_helper_spec.rb +8 -8
  64. data/spec/test_helpers/schema_validator_spec.rb +8 -8
  65. data/spec/utils_spec.rb +6 -6
  66. data/spec/wait_for_spec.rb +2 -2
  67. metadata +44 -53
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
  gemspec
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
2
 
3
- task :default => [:test]
3
+ task default: [:test]
4
4
 
5
5
  require "rake/testtask"
6
6
 
@@ -9,15 +9,3 @@ Rake::TestTask.new do |t|
9
9
  t.libs << "spec"
10
10
  t.pattern = "spec/**/*_spec.rb"
11
11
  end
12
-
13
- task :travis do
14
- mock = 'true' || ENV['FOG_MOCK']
15
- sh("export FOG_MOCK=#{mock} && rake")
16
-
17
- if ENV['COVERAGE']
18
- require 'coveralls/rake/task'
19
-
20
- Coveralls::RakeTask.new
21
- Rake::Task["coveralls:push"].invoke
22
- end
23
- end
data/changelog.md CHANGED
@@ -1,3 +1,17 @@
1
+ 2.4.0 01/03/2024
2
+ ==========================================================
3
+
4
+ - fixes for caching/restoring collection attributes
5
+ - add explicit CRUD methods to models, make returns more consistent
6
+ - add filter_attributes method
7
+ - allow cache loading with aliases
8
+ - update rubocop config and apply styles/fixes
9
+ - fix minitest compatibility
10
+ - remove coveralls
11
+ - fixes for method delegation for ruby 3.x
12
+ - update ruby versions in test matrix
13
+
14
+
1
15
  2.3.0 03/08/2022
2
16
  ==========================================================
3
17
 
data/fog-core.gemspec CHANGED
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require "fog/core/version"
5
6
 
@@ -15,26 +16,28 @@ Gem::Specification.new do |spec|
15
16
 
16
17
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.required_ruby_version = '>= 2.0.0'
21
+ spec.required_ruby_version = ">= 2.0"
22
22
 
23
23
  spec.add_dependency("builder")
24
- spec.add_dependency("mime-types")
25
24
  spec.add_dependency("excon", "~> 0.71")
26
25
  spec.add_dependency("formatador", ">= 0.2", "< 2.0")
26
+ spec.add_dependency("mime-types")
27
27
 
28
28
  # https://github.com/fog/fog-core/issues/206
29
29
  # spec.add_dependency("xmlrpc") if RUBY_VERSION.to_s >= "2.4"
30
30
 
31
- spec.add_development_dependency("tins") if RUBY_VERSION.to_s > "2.0"
32
- spec.add_development_dependency("coveralls")
33
31
  spec.add_development_dependency("minitest")
34
32
  spec.add_development_dependency("minitest-stub-const")
35
33
  spec.add_development_dependency("pry")
36
34
  spec.add_development_dependency("rake")
37
35
  spec.add_development_dependency("rubocop")
36
+ spec.add_development_dependency("rubocop-minitest")
37
+ spec.add_development_dependency("rubocop-rake")
38
38
  spec.add_development_dependency("thor")
39
+ spec.add_development_dependency("tins")
39
40
  spec.add_development_dependency("yard")
41
+
42
+ spec.metadata["rubygems_mfa_required"] = "true"
40
43
  end
@@ -53,12 +53,13 @@ module Fog
53
53
  def ssh_ip_address
54
54
  return public_ip_address unless @ssh_ip_address
55
55
  return @ssh_ip_address.call(self) if @ssh_ip_address.is_a?(Proc)
56
+
56
57
  @ssh_ip_address
57
58
  end
58
59
 
59
60
  def ssh_options
60
61
  @ssh_options ||= {}
61
- ssh_options = @ssh_options.merge(:port => ssh_port)
62
+ ssh_options = @ssh_options.merge(port: ssh_port)
62
63
  if private_key
63
64
  ssh_options[:key_data] = [private_key]
64
65
  ssh_options[:auth_methods] = %w(publickey)
@@ -89,9 +90,12 @@ module Fog
89
90
  end
90
91
 
91
92
  def sshable?(options = {})
92
- result = ready? && !ssh_ip_address.nil? && !!Timeout.timeout(sshable_timeout) { ssh("pwd", options) }
93
+ return false unless ready? && ssh_ip_address
94
+
95
+ Timeout.timeout(sshable_timeout) { ssh("pwd", options) }
93
96
  @sshable_timeout = nil
94
- result
97
+
98
+ true
95
99
  rescue SystemCallError
96
100
  false
97
101
  rescue Net::SSH::AuthenticationFailed, Net::SSH::Disconnect
data/lib/fog/compute.rb CHANGED
@@ -22,10 +22,10 @@ module Fog
22
22
  version = attributes.delete(:version)
23
23
  version = version.to_s.downcase.to_sym unless version.nil?
24
24
  if version == :v1
25
- error_message = 'DigitalOcean V1 is deprecated.Please use `:version => :v2` attribute to use Next Gen Cloud Servers.'
25
+ error_message = "DigitalOcean V1 is deprecated.Please use `:version => :v2` attribute to use Next Gen Cloud Servers."
26
26
  raise error_message
27
27
  else
28
- require 'fog/digitalocean/compute'
28
+ require "fog/digitalocean/compute"
29
29
  Fog::Compute::DigitalOcean.new(attributes)
30
30
  end
31
31
  else
@@ -7,6 +7,7 @@ module Fog
7
7
 
8
8
  def load(associations)
9
9
  return unless associations.kind_of?(Array)
10
+
10
11
  associations.each do |association|
11
12
  self << association
12
13
  end
@@ -7,6 +7,13 @@ module Fog
7
7
  class Default
8
8
  attr_reader :model, :name, :squash, :aliases, :default, :as
9
9
 
10
+ # @param [Klass] model model class
11
+ # @param [Symbol] name name of the attribute
12
+ # @param [Hash] options attribute options
13
+ # @option options [Symbol] :squash
14
+ # @option options [::Array] :aliases
15
+ # @option options [Object] :default
16
+ # @option options [Object] :as
10
17
  def initialize(model, name, options)
11
18
  @model = model
12
19
  @model.attributes << name
@@ -25,6 +25,14 @@ module Fog
25
25
  @masks ||= {}
26
26
  end
27
27
 
28
+ # Defines a new attribute
29
+ # @param [Symbol] name attribute name
30
+ # @param [Hash] options (see {Default#initialize})
31
+ # @option options [Symbol, ::String] :type attribute type (see {Attributes})
32
+ # @option options [Symbol] :squash
33
+ # @option options [::Array] :aliases
34
+ # @option options [Object] :default
35
+ # @option options [Object] :as
28
36
  def attribute(name, options = {})
29
37
  type = options.fetch(:type, "default").to_s.capitalize
30
38
  Fog::Attributes.const_get(type).new(self, name, options)
@@ -125,9 +133,13 @@ module Fog
125
133
  send("#{identity_name}=", new_identity)
126
134
  end
127
135
 
136
+ # Merges attributes into self
137
+ # @note Ignored attributes are not merged (see {ClassMethods.ignored_attributes})
138
+ # @return [self]
128
139
  def merge_attributes(new_attributes = {})
129
140
  new_attributes.each_pair do |key, value|
130
141
  next if self.class.ignored_attributes.include?(key)
142
+
131
143
  if self.class.aliases[key]
132
144
  send("#{self.class.aliases[key]}=", value)
133
145
  elsif self.respond_to?("#{key}=", true)
@@ -139,6 +151,18 @@ module Fog
139
151
  self
140
152
  end
141
153
 
154
+ # Filters attributes by selected attribute names
155
+ # @note In some cases we want to easily get subset of model attributes
156
+ # @note Hash#slice requires Ruby >= 2.5.0
157
+ # @param [Symbol] selected attribute names
158
+ # @return [Hash] new hash with selected attributes
159
+ def filter_attributes(*selected)
160
+ filtered = attributes.select { |a, _| selected.include?(a) }
161
+
162
+ # we should use getters instead of direct accessing attributes hash
163
+ filtered.each_key { |k| filtered[k] = send(k) }
164
+ end
165
+
142
166
  # Returns true if a remote resource has been assigned an
143
167
  # identity and we can assume it has been persisted.
144
168
  #
@@ -166,14 +190,15 @@ module Fog
166
190
  if missing.length == 1
167
191
  raise(ArgumentError, "#{missing.first} is required for this operation")
168
192
  elsif missing.any?
169
- raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
193
+ raise(ArgumentError, "#{missing[0...-1].join(', ')} and #{missing[-1]} are required for this operation")
170
194
  end
171
195
  end
172
196
 
173
197
  def requires_one(*args)
174
198
  missing = missing_attributes(args)
175
199
  return unless missing.length == args.length
176
- raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
200
+
201
+ raise(ArgumentError, "#{missing[0...-1].join(', ')} or #{missing[-1]} are required for this operation")
177
202
  end
178
203
 
179
204
  protected
@@ -181,7 +206,7 @@ module Fog
181
206
  def missing_attributes(args)
182
207
  missing = []
183
208
  ([:service] | args).each do |arg|
184
- missing << arg unless send("#{arg}") || attributes.key?(arg)
209
+ missing << arg unless send(arg.to_s) || attributes.key?(arg)
185
210
  end
186
211
  missing
187
212
  end
@@ -93,6 +93,9 @@ module Fog
93
93
  # see the +namespace_prefix=+ method.
94
94
  SANDBOX = ENV["HOME"] ? File.expand_path("~/.fog-cache") : File.expand_path(".fog-cache")
95
95
 
96
+ # required attributes to load model from cache
97
+ REQUIRED_ATTRIBUTES = [:identity, :collection_klass, :collection_attrs, :model_klass, :model_attrs].freeze
98
+
96
99
  # when a resource is used such as `server.cache.dump` the model klass is passed in
97
100
  # so that it can be identified from a different session.
98
101
  attr_reader :model
@@ -112,26 +115,34 @@ module Fog
112
115
  # collection_klass and model_klass should be the same across all instances
113
116
  # choose a valid cache record from the dump to use as a sample to deterine
114
117
  # which collection/model to instantiate.
115
- sample_path = cache_files.detect{ |path| valid_for_load?(path) }
116
- model_klass = const_get_compat(load_cache(sample_path)[:model_klass])
117
- collection_klass = const_get_compat(load_cache(sample_path)[:collection_klass]) if load_cache(sample_path)[:collection_klass]
118
+ sample_path = cache_files.detect { |path| valid_for_load?(path) }
119
+ model_klass = Object.const_get(load_cache(sample_path)[:model_klass])
120
+ collection_klass = Object.const_get(load_cache(sample_path)[:collection_klass]) if load_cache(sample_path)[:collection_klass]
118
121
 
119
122
  # Load the cache data into actual ruby instances
120
123
  loaded = cache_files.map do |path|
121
- model_klass.new(load_cache(path)[:attrs]) if valid_for_load?(path)
122
- end.compact
124
+ next unless valid_for_load?(path)
123
125
 
124
- # Set the collection and service so they can be reloaded/connection is set properly.
125
- # See https://github.com/fog/fog-aws/issues/354#issuecomment-286789702
126
- loaded.each do |i|
127
- i.collection = collection_klass.new(:service => service) if collection_klass
128
- i.instance_variable_set(:@service, service)
129
- end
126
+ cache = load_cache(path)
127
+
128
+ # make sure attributes are not nil
129
+ cache[:collection_attrs] ||= {}
130
+ cache[:model_attrs] ||= {}
131
+
132
+ m = model_klass.new(cache[:model_attrs])
133
+
134
+ # Set the collection and service so they can be reloaded/connection is set properly.
135
+ # See https://github.com/fog/fog-aws/issues/354#issuecomment-286789702
136
+ m.instance_variable_set(:@service, service)
137
+ m.collection = collection_klass.new(cache[:collection_attrs].merge(service: service)) if collection_klass
138
+
139
+ m
140
+ end.compact
130
141
 
131
142
  # uniqe-ify based on the total of attributes. duplicate cache can exist due to
132
143
  # `model#identity` not being unique. but if all attributes match, they are unique
133
144
  # and shouldn't be loaded again.
134
- uniq_loaded = uniq_w_block(loaded) { |i| i.attributes }
145
+ uniq_loaded = loaded.uniq { |i| i.attributes }
135
146
  if uniq_loaded.size != loaded.size
136
147
  Fog::Logger.warning("Found duplicate items in the cache. Expire all & refresh cache soon.")
137
148
  end
@@ -142,38 +153,18 @@ module Fog
142
153
  uniq_loaded
143
154
  end
144
155
 
145
- # :nodoc: compatability for 1.8.7 1.9.3
146
- def self.const_get_compat(strklass)
147
- # https://stackoverflow.com/questions/3163641/get-a-class-by-name-in-ruby
148
- strklass.split('::').inject(Object) do |mod, class_name|
149
- mod.const_get(class_name)
150
- end
151
- end
152
-
153
- # :nodoc: compatability for 1.8.7 1.9.3
154
- def self.uniq_w_block(arr)
155
- ret, keys = [], []
156
- arr.each do |x|
157
- key = block_given? ? yield(x) : x
158
- unless keys.include? key
159
- ret << x
160
- keys << key
161
- end
162
- end
163
- ret
164
- end
165
-
166
156
  # method to determine if a path can be loaded and is valid fog cache format.
167
157
  def self.valid_for_load?(path)
168
158
  data = load_cache(path)
169
159
  if data && data.is_a?(Hash)
170
- if [:identity, :model_klass, :collection_klass, :attrs].all? { |k| data.keys.include?(k) }
171
- return true
172
- else
173
- Fog::Logger.warning("Found corrupt items in the cache: #{path}. Expire all & refresh cache soon.\n\nData:#{File.read(path)}")
174
- return false
175
- end
160
+ missing_attrs = REQUIRED_ATTRIBUTES.reject { |k| data.keys.include?(k) }
161
+ return true if missing_attrs.empty?
162
+
163
+ Fog::Logger.warning("Found corrupt items in the cache: #{path}. Expire all & refresh cache soon.\n\nMissing: #{missing_attrs}.\nData:\n#{File.read(path)}")
164
+ return false
176
165
  end
166
+
167
+ false
177
168
  end
178
169
 
179
170
  # creates on-disk cache of this specific +model_klass+ and +@service+
@@ -193,12 +184,23 @@ module Fog
193
184
  FileUtils.rm_rf(SANDBOX)
194
185
  end
195
186
 
187
+ # Load YAML file with aliases
188
+ # @note Starting from Ruby 3.1 we must explicitly tell Psych to allow aliases
189
+ def self.yaml_load(path)
190
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1.0")
191
+ YAML.load(path, aliases: true)
192
+ else
193
+ YAML.load(path)
194
+ end
195
+ end
196
+
196
197
  # loads yml cache from path on disk, used
197
198
  # to initialize Fog models.
198
199
  def self.load_cache(path)
199
200
  @memoized ||= {}
200
201
  return @memoized[path] if @memoized[path]
201
- @memoized[path] = YAML.load(File.read(path))
202
+
203
+ @memoized[path] = yaml_load(File.read(path))
202
204
  end
203
205
 
204
206
  def self.namespace_prefix=(name)
@@ -222,13 +224,13 @@ module Fog
222
224
 
223
225
  mpath = File.join(SANDBOX, namespace_prefix, "metadata.yml")
224
226
  to_write = if File.exist?(mpath)
225
- YAML.dump(YAML.load(File.read(mpath)).merge!(h))
226
- else
227
- YAML.dump(h)
228
- end
227
+ YAML.dump(yaml_load(File.read(mpath)).merge!(h))
228
+ else
229
+ YAML.dump(h)
230
+ end
229
231
 
230
232
  mdir = File.join(SANDBOX, namespace_prefix)
231
- FileUtils.mkdir_p(mdir) if !File.exist?(mdir)
233
+ FileUtils.mkdir_p(mdir)
232
234
 
233
235
  File.open(mpath, "w") { |f| f.write(to_write) }
234
236
  end
@@ -237,10 +239,9 @@ module Fog
237
239
  def self.metadata
238
240
  mpath = File.join(SANDBOX, namespace_prefix, "metadata.yml")
239
241
  if File.exist?(mpath)
240
- metadata = YAML.load(File.read(mpath))
241
- return metadata
242
+ yaml_load(File.read(mpath))
242
243
  else
243
- return {}
244
+ {}
244
245
  end
245
246
  end
246
247
 
@@ -249,11 +250,10 @@ module Fog
249
250
 
250
251
  raise CacheDir.new("Must set an explicit identifier/name for this cache. Example: 'serviceX-regionY'") unless namespace_prefix
251
252
 
252
- ns = File.join(SANDBOX, namespace_prefix, service.class.to_s, model_klass.to_s)
253
- ns = safe_path(ns)
253
+ File.join(SANDBOX, namespace_prefix, safe_class_path(service.class), safe_class_path(model_klass))
254
254
  end
255
255
 
256
- def self.safe_path(klass)
256
+ def self.safe_class_path(klass)
257
257
  klass.to_s.gsub("::", "_").downcase
258
258
  end
259
259
 
@@ -269,10 +269,13 @@ module Fog
269
269
  self.class.create_namespace(model.class, model.service)
270
270
  end
271
271
 
272
- data = { :identity => model.identity,
273
- :model_klass => model.class.to_s,
274
- :collection_klass => model.collection && model.collection.class.to_s,
275
- :attrs => model.attributes }
272
+ data = {
273
+ identity: model.identity,
274
+ model_klass: model.class.to_s,
275
+ collection_klass: model.collection && model.collection.class.to_s,
276
+ collection_attrs: model.collection && model.collection.attributes,
277
+ model_attrs: model.attributes
278
+ }
276
279
 
277
280
  File.open(dump_to, "w") { |f| f.write(YAML.dump(data)) }
278
281
  end
@@ -11,6 +11,7 @@ module Fog
11
11
 
12
12
  Array.public_instance_methods(false).each do |method|
13
13
  next if [:reject, :select, :slice, :clear, :inspect].include?(method.to_sym)
14
+
14
15
  class_eval <<-EOS, __FILE__, __LINE__
15
16
  def #{method}(*args)
16
17
  unless @loaded
@@ -18,6 +19,7 @@ module Fog
18
19
  end
19
20
  super
20
21
  end
22
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
21
23
  EOS
22
24
  end
23
25
 
@@ -30,6 +32,7 @@ module Fog
30
32
  data = super
31
33
  self.clone.clear.concat(data)
32
34
  end
35
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
33
36
  EOS
34
37
  end
35
38
 
@@ -52,7 +55,7 @@ module Fog
52
55
  end
53
56
 
54
57
  def destroy(identity)
55
- new(:identity => identity).destroy
58
+ new(identity: identity).destroy
56
59
  end
57
60
 
58
61
  # Creates a new Fog::Collection based around the passed service
@@ -85,10 +88,11 @@ module Fog
85
88
  unless attributes.is_a?(::Hash)
86
89
  raise ArgumentError, "Initialization parameters must be an attributes hash, got #{attributes.class} #{attributes.inspect}"
87
90
  end
91
+
88
92
  model.new(
89
93
  {
90
- :collection => self,
91
- :service => service
94
+ collection: self,
95
+ service: service
92
96
  }.merge(attributes)
93
97
  )
94
98
  end
@@ -112,6 +116,7 @@ module Fog
112
116
  all
113
117
  end
114
118
  end
119
+
115
120
  # Base class for collection classes whose 'all' method returns only a single
116
121
  # page of results and passes the 'Marker' option along as
117
122
  # self.filters[:marker]
@@ -120,6 +125,7 @@ module Fog
120
125
  if block_given?
121
126
  Kernel.loop do
122
127
  break unless filters[:marker]
128
+
123
129
  page = all(collection_filters)
124
130
  # We need to explicitly use the base 'each' method here on the page,
125
131
  # otherwise we get infinite recursion
@@ -52,7 +52,7 @@ module Fog
52
52
 
53
53
  params[:debug_response] = true unless params.key?(:debug_response)
54
54
  params[:headers] ||= {}
55
- params.merge!(:persistent => params.fetch(:persistent, persistent))
55
+ params.merge!(persistent: params.fetch(:persistent, persistent))
56
56
  params[:headers]["User-Agent"] ||= user_agent
57
57
  @excon = Excon.new(url, params)
58
58
  end
@@ -4,7 +4,7 @@ module Fog
4
4
  class CurrentMachine
5
5
  @lock = Mutex.new
6
6
 
7
- AMAZON_AWS_CHECK_IP = "http://checkip.amazonaws.com"
7
+ AMAZON_AWS_CHECK_IP = "http://checkip.amazonaws.com".freeze
8
8
 
9
9
  def self.ip_address=(ip_address)
10
10
  @lock.synchronize do
@@ -120,7 +120,7 @@ An alternate file may be used by placing its path in the FOG_RC environment vari
120
120
  # End of Fog Credentials File
121
121
  #######################################################
122
122
 
123
- YML
123
+ YML
124
124
  raise Fog::Errors::LoadError, missing_credentials_message
125
125
  end
126
126
  end
@@ -1,8 +1,8 @@
1
1
  module Fog
2
2
  class Logger
3
3
  @channels = {
4
- :deprecation => ::STDERR,
5
- :warning => ::STDERR
4
+ deprecation: ::STDERR,
5
+ warning: ::STDERR
6
6
  }
7
7
 
8
8
  @channels[:debug] = ::STDERR if ENV["DEBUG"]
data/lib/fog/core/mock.rb CHANGED
@@ -25,6 +25,7 @@ module Fog
25
25
 
26
26
  def self.delay=(new_delay)
27
27
  raise ArgumentError, "delay must be non-negative" unless new_delay >= 0
28
+
28
29
  @delay = new_delay
29
30
  end
30
31
 
@@ -32,7 +33,7 @@ module Fog
32
33
  raise Fog::Errors::MockNotImplemented, message
33
34
  end
34
35
 
35
- def self.random_ip(opts = { :version => :v4 })
36
+ def self.random_ip(opts = { version: :v4 })
36
37
  version = opts[:version]
37
38
  if version == :v6
38
39
  bit_length = 128
@@ -92,12 +93,15 @@ module Fog
92
93
  mocked_services = []
93
94
  Fog.constants.map do |x|
94
95
  next if Fog.autoload?(x)
96
+
95
97
  x_const = Fog.const_get(x)
96
98
  x_const.respond_to?(:constants) && x_const.constants.map do |y|
97
99
  next if x_const.autoload?(y)
100
+
98
101
  y_const = x_const.const_get(y)
99
102
  y_const.respond_to?(:constants) && y_const.constants.map do |z|
100
103
  next if y_const.autoload?(z)
104
+
101
105
  mocked_services << y_const.const_get(z) if z.to_sym == :Mock
102
106
  end
103
107
  end
@@ -105,6 +109,7 @@ module Fog
105
109
 
106
110
  mocked_services.each do |mocked_service|
107
111
  next unless mocked_service.respond_to?(:reset)
112
+
108
113
  mocked_service.reset
109
114
  end
110
115
  end
@@ -21,6 +21,33 @@ module Fog
21
21
  merge_attributes(attribs)
22
22
  end
23
23
 
24
+ # Creates new or updates existing model
25
+ # @return [self]
26
+ def save
27
+ persisted? ? update : create
28
+ end
29
+
30
+ # Creates new entity from model
31
+ # @raise [Fog::Errors::NotImplemented] you must implement #create method in child class and return self
32
+ # @return [self]
33
+ def create
34
+ raise Fog::Errors::NotImplemented, "Implement method #create for #{self.class}. Method must return self"
35
+ end
36
+
37
+ # Updates new entity with model
38
+ # @raise [Fog::Errors::NotImplemented] you must implement #update method in child class and return self
39
+ # @return [self]
40
+ def update
41
+ raise Fog::Errors::NotImplemented, "Implement method #update for #{self.class}. Method must return self"
42
+ end
43
+
44
+ # Destroys entity by model identity
45
+ # @raise [Fog::Errors::NotImplemented] you must implement #destroy method in child class and return self
46
+ # @return [self]
47
+ def destroy
48
+ raise Fog::Errors::NotImplemented, "Implement method #destroy for #{self.class}. Method must return self"
49
+ end
50
+
24
51
  def cache
25
52
  Fog::Cache.new(self)
26
53
  end
@@ -41,6 +68,8 @@ module Fog
41
68
  end
42
69
  end
43
70
 
71
+ # @return [self] if model successfully reloaded
72
+ # @return [nil] if something went wrong or model was not found
44
73
  def reload
45
74
  requires :identity
46
75
 
@@ -61,6 +90,7 @@ module Fog
61
90
 
62
91
  def symbolize_keys(hash)
63
92
  return nil if hash.nil?
93
+
64
94
  hash.reduce({}) do |options, (key, value)|
65
95
  options[(key.to_sym rescue key) || key] = value
66
96
  options
@@ -69,6 +99,7 @@ module Fog
69
99
 
70
100
  def wait_for(timeout = Fog.timeout, interval = Fog.interval, &block)
71
101
  reload_has_succeeded = false
102
+
72
103
  duration = Fog.wait_for(timeout, interval) do # Note that duration = false if it times out
73
104
  if reload
74
105
  reload_has_succeeded = true
@@ -77,11 +108,9 @@ module Fog
77
108
  false
78
109
  end
79
110
  end
80
- if reload_has_succeeded
81
- return duration # false if timeout; otherwise {:duration => elapsed time }
82
- else
83
- raise Fog::Errors::Error, "Reload failed, #{self.class} #{identity} not present."
84
- end
111
+ raise Fog::Errors::Error, "Reload failed, #{self.class} #{identity} not present." unless reload_has_succeeded
112
+
113
+ duration # false if timeout; otherwise {:duration => elapsed time }
85
114
  end
86
115
  end
87
116
  end
@@ -18,11 +18,11 @@ module Fog
18
18
  private
19
19
 
20
20
  def underscore_name(string)
21
- string.gsub(/::/, '/').
22
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
23
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
24
- tr("-", "_").
25
- downcase
21
+ string.gsub(/::/, "/")
22
+ .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
23
+ .gsub(/([a-z\d])([A-Z])/,'\1_\2')
24
+ .tr("-", "_")
25
+ .downcase
26
26
  end
27
27
  end
28
28
 
@@ -49,7 +49,7 @@ module Fog
49
49
  [to_s, constant_string].join("::")
50
50
  else
51
51
  provider = to_s.split("::").last
52
- Fog::Logger.deprecation("Unable to load #{[to_s, constant_string].join("::")}")
52
+ Fog::Logger.deprecation("Unable to load #{[to_s, constant_string].join('::')}")
53
53
  Fog::Logger.deprecation(
54
54
  format(
55
55
  Fog::ServicesMixin::E_SERVICE_PROVIDER_CONSTANT,
@@ -57,7 +57,7 @@ module Fog
57
57
  provider: provider
58
58
  )
59
59
  )
60
- ['Fog', constant_string, provider].join("::")
60
+ ["Fog", constant_string, provider].join("::")
61
61
  end
62
62
  end
63
63
  end