Skip to content

Instantly share code, notes, and snippets.

@janko
Last active July 24, 2018 08:34
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janko/df50fd251b591752076a to your computer and use it in GitHub Desktop.
Save janko/df50fd251b591752076a to your computer and use it in GitHub Desktop.
Ruby keyword arguments advantages and use cases
####
# 1. Simple assertion of required arguments
####
# - You can forget #fetch
# - You get a better error, and always on the line where method is defined
def search(options = {})
query = options.fetch(:query)
end
search() # => KeyError: key not found :query
def search(query:)
# ...
end
search() # => ArgumentError: missing keyword: query
####
# 2. Easy providing of default values
####
# - Using #fetch can be cumbersome
def search(page: 1, per_page: nil, all: true)
# ...
end
def search(options = {})
options[:page] ||= 1
options[:all] ||= true # problem: gets executed when `all: false` is passed
end
def search(options = {})
options[:page] = options.fetch(:page) { 1 }
options[:all] = options.fetch(:all) { true }
end
####
# 3. Shortness
####
def search(options = {})
quizzes = Quiz.dataset
quizzes = quizzes.search(options[:q]) if options[:q]
quizzes = quizzes.where(category: options[:category]) if options[:category]
quizzes = quizzes.paginate(Integer(options[:page]), Integer(options[:per_page])) if options[:per_page]
quizzes
end
def search(q: nil, category: nil, page: 1, per_page: nil)
quizzes = Quiz.dataset
quizzes = quizzes.search(q) if q
quizzes = quizzes.where(category: category) if category
quizzes = quizzes.paginate(Integer(page), Integer(per_page)) if per_page
quizzes
end
####
# 4. You can easily extract "special" options
####
def make_request(params = {})
raise_errors = params.fetch(:raise_errors) { true }
params.delete(:raise_errors)
response = api.request(params)
raise HTTPError if response.status.between?(400, 500) && raise_errors
response
end
def make_request(raise_errors: true, **params)
response = api.request(params)
raise HTTPError if response.status.between?(400, 500) && raise_errors
response
end
####
# 5. Sometimes it can really help you write elegant code
####
# - `tries` cannot be in the method body, because retry executes the whole method again, so `tries` gets reinitialized
def get_weather_report(tries: 3)
WeatherApi.get_report
rescue Timeout::Error
tries -= 1
retry if tries > 0
raise
end
####
# 6. It's completely interchangable with Hash as options
####
# - Everything below works
def search(**options)
options #=> Hash
make_request("search", options)
make_request("search", **options)
end
def search(options = {})
options #=> Hash
make_request("search", options)
make_request("search", **options)
end
make_request(options = {})
make_request(**options)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment