-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: use generator methods, and class instance variables to separate duties between classes #143
base: main
Are you sure you want to change the base?
Conversation
…rate duties between classes
Style/ClassVars: | ||
Enabled: false | ||
|
||
Style/GlobalVars: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The proscription against class and global variables is in general pretty sensible. I haven't yet digested enough of this PR to know whether they can be done without, but if not, I think the Rubocop checks should be disabled on a linewise basis rather than disabling them globally. For example, one a line with a global variable like $options
, you can append a comment:
# rubocop:disable Style/GlobalVars
...to turn off the warning for that line only. It's a bit noisy, but I think it's better to draw attention to places where the usual style rules are being overridden by necessity.
...Also, when I check out your branch and search the codebase for the string @@
, I don't find any instances. I would expect to find some if Ruby class variables are being employed somewhere. Is it actually necessary to disable the Style/ClassVars
rule at all?
def any_resource_instance | ||
resource_instances.first | ||
def initialize(options) | ||
$options = options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original code stored the options in an instance variable rather than a global variable, which would be the more normal practice. This PR is a little large for me to take in all at once, so I'll just ask here: What other code needs to access the options passed in here via the global variable $options
?
...Coming back to this comment a bit later, I have some ideas for how to minimize the drawbacks of the use of a global variable. (That is, if its use can't be easily eliminated.)
First, it would be cleaner if the code that instantiates the DatadogBackup::Cli
object assigns the options to the global variable rather than leaving it up to the class to do it. I see the code that does the instantiation in bin/datadog_backup
:
DatadogBackup::Cli.new(prereqs(defaults)).run!
I'd suggest instead something like:
$options = prereqs(defaults).freeze
DatadogBackup::Cli.new($options).run!
I see also that the Cli
class only cares about the resources
, force_restore
, and action
option values. The class could be constructed in a more standard style be storing these as instance variables in the class.
def initialize(resources:, force_restore:, action:, **)
@resources = resources
@force_restore = force_restore
@action = action
end
(The **
will cause any unknown keys in the hash to be ignored.)
Then in the rest of the class you can write just @resources
instead of $options[:resources]
, and likewise for the other keys.
The above only applies if no other code is going to update the options on the fly, which appears to be the case.
def diffs | ||
$options[:resources].each do |resource| | ||
resource.all.each do |resource_instance| | ||
next if resource_instance.diff.nil? || resource_instance.diff.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem like ActiveSupport is available in this repo...? If it is, you can combine these two tests into just:
next if resource_instance.diff.blank?
@banlist.each do |key| | ||
outhash.delete(key) # delete returns the value at the deleted key, hence the tap wrapper | ||
end | ||
outhash | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method could be more concisely implemented as:
@banlist.each_with_object(hash.dup) do |key, outhash|
outhash.delete(key)
end
file.write(data) | ||
ensure | ||
file.close | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The File.open
method can be given a block, and will take care of closing the file afterwards:
::File.open(filename, 'w') do |file|
file.write(data)
end
|
||
def initialize | ||
@client = Faraday.new( | ||
url: ENV.fetch('DD_SITE_URL', 'https://api.datadoghq.com/'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default url might be better stored as a class constant, eg:
DEFAULT_DD_SITE_URL = 'https://api.datadoghq.com/'
And later:
url: ENV.fetch('DD_SITE_URL', DEFAULT_DD_SITE_URL)
@all ||= get_all.map do |resource| | ||
new_resource(id: resource.fetch(@id_keyname), body: resource) | ||
end | ||
LOGGER.info "Found #{@all.length} #{@api_resource_name}s in Datadog" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logging will happen even if the get_all
response has already been cached in the @all
instance variable. Is that intended?
@get_all = @dig_in_list_body ? body.fetch(*@dig_in_list_body) : body | ||
end | ||
|
||
# Fetch the specified resource from Datadog and remove the @banlist elements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment accurate? The method is very short and doesn't seem to affect @banlist
at all.
end | ||
|
||
def backup_all | ||
all.map(&:backup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see only one place backup_all
is called, and the result is discarded. If the result of calling backup
is not needed, you can signal that more explicitly by saying all.each(&:backup)
here.
class Resources | ||
## | ||
# Meant to be mixed into DatadogBackup::Resources | ||
# Relies on $options[:backup_dir] and $options[:output_format] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see $options[:backup_dir]
mentioned in this file; is this comment accurate?
@@ -3,142 +3,4 @@ | |||
require 'spec_helper' | |||
|
|||
describe DatadogBackup::Cli do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is now nearly empty and does no testing; can it be removed?
@@ -0,0 +1,4 @@ | |||
# frozen_string_literal: true | |||
|
|||
describe DatadogBackup::Client do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file necessary? It doesn't seem to do anything.
@strategy = FactoryBot.strategy_by_name(:create).new | ||
end | ||
|
||
#delegate :association, to: :@strategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to just delete this line probably.
Uses the factory method to manage the differences and commonalities in the DataDog API.
The major features of this refactor are:
TODO: