Update Rubocop and address the addressable todos

This is a big step forward in our Rubocop setup. I addressed all of the todos
from the current version of Rubocop that made sense to. The only things that
remain are metrics and one cop that relies on the line length metric to work.

I made some judgment calls on disabling a few cops:

1. The `Layout/IndentHeredoc` cop wants you to either use the squiggly heredoc
   from Ruby 2.3 or introduce a library. Since we are a low-level library that
   is used as a transitive dependency, we cannot introduce another library as a
   dependence, so that option is out. Also, we support Rubies back to 2.0
   currently, so using the squiggly heredoc isn't an option. Once we remove
   support for Rubies older than 2.3, we can switch to the squiggly heredoc cop.
2. The `Naming/FileName` cop was reporting false positives for a few files in
   the repository, so I disabled it on those files.
3. The `Style/DoubleNegation` cop reports lints on a few cases where we use
   double negation. Given the very generic nature of Hashie, the double-negation
   is the easiest, clearest way to express that we want an item to be a Boolean.
   I disabled the cop because we exist in the gray area where this makes sense.
This commit is contained in:
Michael Herold 2018-02-03 10:23:14 -06:00
parent 8fc10095fc
commit 5a6ffc7e2d
No known key found for this signature in database
GPG Key ID: 0325A44E1EA06F99
47 changed files with 230 additions and 217 deletions

View File

@ -4,7 +4,22 @@ AllCops:
- Rakefile
Exclude:
- .bundle/**/*
- bin/**/*
- vendor/**/*
inherit_from: .rubocop_todo.yml
# Disabled until we can use the squiggly heredoc (after deprecating Ruby <2.3)
Layout/IndentHeredoc:
Enabled: false
Naming/FileName:
Exclude:
- 'Dangerfile'
- '**/Gemfile'
- '**/Rakefile'
# Disabled because of the very generic nature of Hashie. In the cases where we
# use double negation, there isn't a means that as succinct of doing the type of
# boolean casting that we do.
Style/DoubleNegation:
Enabled: false

View File

@ -1,19 +1,19 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-02-04 16:33:11 -0600 using RuboCop version 0.34.2.
# on 2018-02-07 19:58:08 -0600 using RuboCop version 0.52.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 2
Lint/NestedMethodDefinition:
Exclude:
- 'lib/hashie/extensions/indifferent_access.rb'
# Offense count: 10
# Offense count: 9
Metrics/AbcSize:
Max: 29
Max: 26
# Offense count: 57
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 620
# Offense count: 2
# Configuration parameters: CountComments.
@ -24,11 +24,6 @@ Metrics/ClassLength:
Metrics/CyclomaticComplexity:
Max: 11
# Offense count: 246
# Configuration parameters: AllowURI, URISchemes.
Metrics/LineLength:
Max: 170
# Offense count: 17
# Configuration parameters: CountComments.
Metrics/MethodLength:
@ -43,27 +38,19 @@ Metrics/ModuleLength:
Metrics/PerceivedComplexity:
Max: 10
# Offense count: 2
Style/CaseEquality:
Exclude:
- 'lib/hashie/hash.rb'
# Offense count: 37
# Configuration parameters: Exclude.
# Offense count: 36
Style/Documentation:
Enabled: false
# Offense count: 10
Style/DoubleNegation:
Exclude:
- 'lib/hashie/dash.rb'
- 'lib/hashie/extensions/dash/indifferent_access.rb'
- 'lib/hashie/extensions/method_access.rb'
- 'lib/hashie/mash.rb'
- 'spec/hashie/extensions/coercion_spec.rb'
# Offense count: 7
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues.
Style/HashSyntax:
Enabled: false
Style/IfUnlessModifier:
Exclude:
- 'lib/hashie/extensions/dash/property_translation.rb'
- 'lib/hashie/extensions/strict_key_access.rb'
# Offense count: 256
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 170

View File

@ -40,6 +40,7 @@ scheme are considered to be bugs.
### Miscellaneous
* [#433](https://github.com/intridea/hashie/pull/433): Update Rubocop to the most recent version - [@michaelherold](https://github.com/michaelherold).
* [#434](https://github.com/intridea/hashie/pull/434): Add documentation around Mash sub-Hashes - [@michaelherold](https://github.com/michaelherold).
* [#439](https://github.com/intridea/hashie/pull/439): Add an integration spec for Elasticsearch - [@michaelherold](https://github.com/michaelherold).
* Your contribution here.

10
Gemfile
View File

@ -4,23 +4,25 @@ gemspec
group :development do
gem 'benchmark-ips'
gem 'pry'
gem 'pry-stack_explorer', platforms: [:ruby_19, :ruby_20, :ruby_21]
gem 'rubocop', '0.34.2'
gem 'guard', '~> 2.6.1'
gem 'guard-rspec', '~> 4.3.1', require: false
gem 'guard-yield', '~> 0.1.0', require: false
gem 'pry'
gem 'pry-stack_explorer', platforms: %i[ruby_19 ruby_20 ruby_21]
gem 'rubocop', '0.52.1'
end
group :test do
# ActiveSupport required to test compatibility with ActiveSupport Core Extensions.
# rubocop:disable Bundler/DuplicatedGem
require File.expand_path('../lib/hashie/extensions/ruby_version', __FILE__)
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
gem 'activesupport', '~> 5.x', require: false
else
gem 'activesupport', '~> 4.x', require: false
end
# rubocop:enable Bundler/DuplicatedGem
gem 'codeclimate-test-reporter', '~> 1.0', require: false
gem 'rspec-core', '~> 3.1.7'
gem 'danger-changelog', '~> 0.1.0', require: false
gem 'rspec-core', '~> 3.1.7'
end

View File

@ -24,9 +24,9 @@ task :integration_specs do
run_all_integration_specs(handler: handler, logger: ->(msg) { puts msg })
if status_codes.any?
$stderr.puts "#{status_codes.size} integration test(s) failed"
warn "#{status_codes.size} integration test(s) failed"
exit status_codes.last
end
end
task default: [:rubocop, :spec, :integration_specs]
task default: %i[rubocop spec integration_specs]

View File

@ -1,7 +1,7 @@
#!/usr/bin/env ruby
require "bundler/setup"
require "hashie"
require 'bundler/setup'
require 'hashie'
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
@ -10,5 +10,5 @@ require "hashie"
# require "pry"
# Pry.start
require "irb"
require 'irb'
IRB.start

View File

@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
gem.license = 'MIT'
gem.require_paths = ['lib']
gem.files = %w(.yardopts CHANGELOG.md CONTRIBUTING.md LICENSE README.md UPGRADING.md Rakefile hashie.gemspec)
gem.files = %w[.yardopts CHANGELOG.md CONTRIBUTING.md LICENSE README.md UPGRADING.md Rakefile hashie.gemspec]
gem.files += Dir['lib/**/*.rb']
gem.files += Dir['spec/**/*.rb']
gem.test_files = Dir['spec/**/*.rb']

View File

@ -75,7 +75,7 @@ module Hashie
when Hash
self[key] = self.class.new(self[key], self)
else
fail ChainError, 'Tried to chain into a non-hash key.'
raise ChainError, 'Tried to chain into a non-hash key.'
end
elsif args.any?
merge_store(name, *args)
@ -83,5 +83,16 @@ module Hashie
super
end
end
def respond_to_missing?(method_name, _include_private = false)
method_name = method_name.to_s
if method_name.end_with?('!')
key = method_name[0...-1].to_sym
[NilClass, Clash, Hash].include?(self[key].class)
else
true
end
end
end
end

View File

@ -15,7 +15,7 @@ module Hashie
class Dash < Hash
include Hashie::Extensions::PrettyInspect
alias_method :to_s, :inspect
alias to_s inspect
# Defines a property on the Dash. Options are
# as follows:
@ -48,16 +48,14 @@ module Hashie
define_method(property_assignment) { |value| self.[]=(property_name, value) }
end
if defined? @subclasses
@subclasses.each { |klass| klass.property(property_name, options) }
end
@subclasses.each { |klass| klass.property(property_name, options) } if defined? @subclasses
condition = options.delete(:required)
if condition
message = options.delete(:message) || "is required for #{name}."
required_properties[property_name] = { condition: condition, message: message }
else
fail ArgumentError, 'The :message option should be used with :required option.' if options.key?(:message)
elsif options.key?(:message)
raise ArgumentError, 'The :message option should be used with :required option.'
end
end
@ -111,8 +109,8 @@ module Hashie
assert_required_attributes_set!
end
alias_method :_regular_reader, :[]
alias_method :_regular_writer, :[]=
alias _regular_reader []
alias _regular_writer []=
private :_regular_reader, :_regular_writer
# Retrieve a value from the Dash (will return the
@ -163,11 +161,12 @@ module Hashie
update_attributes(attributes)
self.class.defaults.each_pair do |prop, value|
next unless self[prop].nil?
self[prop] = begin
value.dup
rescue TypeError
value
end if self[prop].nil?
end
end
assert_required_attributes_set!
end
@ -208,11 +207,11 @@ module Hashie
end
def fail_property_required_error!(property)
fail ArgumentError, "The property '#{property}' #{self.class.required_properties[property][:message]}"
raise ArgumentError, "The property '#{property}' #{self.class.required_properties[property][:message]}"
end
def fail_no_property_error!(property)
fail NoMethodError, "The property '#{property}' is not defined for #{self.class.name}."
raise NoMethodError, "The property '#{property}' is not defined for #{self.class.name}."
end
def required?(property)
@ -220,9 +219,9 @@ module Hashie
condition = self.class.required_properties[property][:condition]
case condition
when Proc then !!(instance_exec(&condition))
when Symbol then !!(send(condition))
else !!(condition)
when Proc then !!instance_exec(&condition)
when Symbol then !!send(condition)
else !!condition
end
end
end

View File

@ -10,14 +10,14 @@ module Hashie
Rational => :to_r,
String => :to_s,
Symbol => :to_sym
}
}.freeze
ABSTRACT_CORE_TYPES = if RubyVersion.new(RUBY_VERSION) >= RubyVersion.new('2.4.0')
{ Numeric => [Integer, Float, Complex, Rational] }
else
{
Integer => [Fixnum, Bignum],
Numeric => [Fixnum, Bignum, Float, Complex, Rational]
Integer => [Fixnum, Bignum], # rubocop:disable Lint/UnifiedInteger
Numeric => [Fixnum, Bignum, Float, Complex, Rational] # rubocop:disable Lint/UnifiedInteger
}
end
@ -78,7 +78,7 @@ module Hashie
attrs.each { |key| key_coercions[key] = into }
end
alias_method :coerce_keys, :coerce_key
alias coerce_keys coerce_key
# Returns a hash of any existing key coercions.
def key_coercions
@ -180,7 +180,7 @@ module Hashie
type.new(value)
end
else
fail TypeError, "#{type} is not a coercable type"
raise TypeError, "#{type} is not a coercable type"
end
end

View File

@ -74,7 +74,7 @@ module Hashie
if options[:from]
if property_name == options[:from]
fail ArgumentError, "Property name (#{property_name}) and :from option must not be the same"
raise ArgumentError, "Property name (#{property_name}) and :from option must not be the same"
end
translations_hash[options[:from]] ||= {}
@ -85,10 +85,8 @@ module Hashie
self[name] = with.respond_to?(:call) ? with.call(val) : val
end
end
else
if options[:transform_with].respond_to? :call
transforms[property_name] = options[:transform_with]
end
elsif options[:transform_with].respond_to? :call
transforms[property_name] = options[:transform_with]
end
end
@ -107,11 +105,11 @@ module Hashie
def translations
@translations ||= {}.tap do |h|
translations_hash.each do |(property_name, property_translations)|
if property_translations.size > 1
h[property_name] = property_translations.keys
else
h[property_name] = property_translations.keys.first
end
h[property_name] = if property_translations.size > 1
property_translations.keys
else
property_translations.keys.first
end
end
end
end
@ -119,7 +117,7 @@ module Hashie
def inverse_translations
@inverse_translations ||= {}.tap do |h|
translations_hash.each do |(property_name, property_translations)|
property_translations.keys.each do |k|
property_translations.each_key do |k|
h[k] = property_name
end
end

View File

@ -19,7 +19,7 @@ module Hashie
arg = Integer(arg) if obj.is_a? Array
obj.fetch(arg)
rescue ArgumentError, IndexError, NoMethodError => e
break block.call(arg) if block
break yield(arg) if block
raise UndefinedPathError, "Could not fetch path (#{args.join(' > ')}) at #{arg}", e.backtrace
end
end

View File

@ -19,7 +19,7 @@ module Hashie
_deep_find(key)
end
alias_method :deep_detect, :deep_find
alias deep_detect deep_find
# Performs a depth-first search on deeply nested data structures for
# a key and returns all occurrences of the key.
@ -40,7 +40,7 @@ module Hashie
matches.empty? ? nil : matches
end
alias_method :deep_select, :deep_find_all
alias deep_select deep_find_all
private

View File

@ -61,8 +61,6 @@ module Hashie
Hashie::Extensions::DeepLocate.deep_locate(comparator, self)
end
private
def self._construct_key_comparator(search_key, object)
search_key = search_key.to_s if defined?(::ActiveSupport::HashWithIndifferentAccess) && object.is_a?(::ActiveSupport::HashWithIndifferentAccess)
search_key = search_key.to_s if object.respond_to?(:indifferent_access?) && object.indifferent_access?
@ -71,12 +69,11 @@ module Hashie
->(key, _, _) { key == non_callable_object }
end.call(search_key)
end
private_class_method :_construct_key_comparator
def self._deep_locate(comparator, object, result = [])
if object.is_a?(::Enumerable)
if object.any? { |value| _match_comparator?(value, comparator, object) }
result.push object
end
result.push object if object.any? { |value| _match_comparator?(value, comparator, object) }
(object.respond_to?(:values) ? object.values : object.entries).each do |value|
_deep_locate(comparator, value, result)
end
@ -84,6 +81,7 @@ module Hashie
result
end
private_class_method :_deep_locate
def self._match_comparator?(value, comparator, object)
if object.is_a?(::Hash)
@ -94,6 +92,7 @@ module Hashie
comparator.call(key, value, object)
end
private_class_method :_match_comparator?
end
end
end

View File

@ -20,15 +20,14 @@ module Hashie
def _recursive_merge(hash, other_hash, &block)
other_hash.each do |k, v|
hash[k] = if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
_recursive_merge(hash[k], v, &block)
else
if hash.key?(k) && block_given?
block.call(k, hash[k], v)
else
v.respond_to?(:deep_dup) ? v.deep_dup : v
end
end
hash[k] =
if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
_recursive_merge(hash[k], v, &block)
elsif hash.key?(k) && block_given?
yield(k, hash[k], v)
else
v.respond_to?(:deep_dup) ? v.deep_dup : v
end
end
hash
end

View File

@ -32,12 +32,12 @@ module Hashie
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
alias_method :[]=, :indifferent_writer
alias_method :store, :indifferent_writer
%w(default update replace fetch delete key? values_at).each do |m|
%w[default update replace fetch delete key? values_at].each do |m|
alias_method "regular_#{m}", m unless method_defined?("regular_#{m}")
alias_method m, "indifferent_#{m}"
end
%w(include? member? has_key?).each do |key_alias|
%w[include? member? has_key?].each do |key_alias|
alias_method key_alias, :indifferent_key?
end
@ -75,7 +75,7 @@ module Hashie
# their proper indifferent state. Used when IndifferentAccess
# is injecting itself into member hashes.
def convert!
keys.each do |k|
keys.each do |k| # rubocop:disable Performance/HashEachMethods
regular_writer convert_key(k), indifferent_value(regular_delete(k))
end
self

View File

@ -14,14 +14,12 @@ module Hashie
# mash['string_key'] == mash[:string_key] #=> true
# mash[:symbol_key] == mash['symbol_key'] #=> true
module KeepOriginalKeys
private
def self.included(descendant)
unless descendant <= Hashie::Mash
fail ArgumentError, "#{descendant} is not a kind of Hashie::Mash"
end
raise ArgumentError, "#{descendant} is not a kind of Hashie::Mash" unless descendant <= Hashie::Mash
end
private
# Converts the key when necessary to access the correct Mash key.
#
# @param [Object, String, Symbol] key the key to access.

View File

@ -3,7 +3,7 @@ module Hashie
module Mash
module SafeAssignment
def custom_writer(key, *args) #:nodoc:
fail ArgumentError, "The property #{key} clashes with an existing method." if !key?(key) && respond_to?(key, true)
raise ArgumentError, "The property #{key} clashes with an existing method." if !key?(key) && respond_to?(key, true)
super
end

View File

@ -19,7 +19,7 @@ module Hashie
# @return [void]
# @raise [ArgumentError] when the base class isn't a Mash
def self.included(base)
fail ArgumentError, "#{base} must descent from Hashie::Mash" unless base <= Hashie::Mash
raise ArgumentError, "#{base} must descent from Hashie::Mash" unless base <= Hashie::Mash
end
private

View File

@ -27,7 +27,7 @@ module Hashie
#
# user.not_declared # => NoMethodError
module MethodReader
def respond_to?(name, include_private = false)
def respond_to_missing?(name, include_private = false)
return true if key?(name.to_s) || key?(name.to_sym)
super
end
@ -67,15 +67,13 @@ module Hashie
# h['awesome'] # => 'sauce'
#
module MethodWriter
def respond_to?(name, include_private = false)
def respond_to_missing?(name, include_private = false)
return true if name.to_s =~ /=$/
super
end
def method_missing(name, *args)
if args.size == 1 && name.to_s =~ /(.*)=$/
return self[convert_key(Regexp.last_match[1])] = args.first
end
return self[convert_key(Regexp.last_match[1])] = args.first if args.size == 1 && name.to_s =~ /(.*)=$/
super
end
@ -106,7 +104,7 @@ module Hashie
# h.def? # => false
# h.hji? # => NoMethodError
module MethodQuery
def respond_to?(name, include_private = false)
def respond_to_missing?(name, include_private = false)
if query_method?(name) && indifferent_key?(key_from_query_method(name))
true
else

View File

@ -14,7 +14,7 @@ module Hashie
def perform
template = ERB.new(@content)
template.filename = @file_path
YAML.load template.result
YAML.safe_load template.result
end
def self.perform(file_path)

View File

@ -46,27 +46,26 @@ module Hashie
end
def default(_ = nil)
fail DefaultError
raise DefaultError
end
def default=(_)
fail DefaultError
raise DefaultError
end
def default_proc
fail DefaultError
raise DefaultError
end
def default_proc=(_)
fail DefaultError
raise DefaultError
end
def key(value)
result = super
if result.nil? && (!key?(result) || self[result] != value)
fail KeyError, "key not found with value of #{value.inspect}"
else
result
super.tap do |result|
if result.nil? && (!key?(result) || self[result] != value)
raise KeyError, "key not found with value of #{value.inspect}"
end
end
end
end

View File

@ -44,7 +44,7 @@ module Hashie
# test # => {'abc' => 'def'}
def stringify_keys!(hash)
hash.extend(Hashie::Extensions::StringifyKeys) unless hash.respond_to?(:stringify_keys!)
hash.keys.each do |k|
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
stringify_keys_recursively!(hash[k])
hash[k.to_s] = hash.delete(k)
end

View File

@ -44,7 +44,7 @@ module Hashie
# test # => {:abc => 'def'}
def symbolize_keys!(hash)
hash.extend(Hashie::Extensions::SymbolizeKeys) unless hash.respond_to?(:symbolize_keys!)
hash.keys.each do |k|
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
symbolize_keys_recursively!(hash[k])
hash[k.to_sym] = hash.delete(k)
end

View File

@ -17,7 +17,7 @@ module Hashie
# Converts a mash back to a hash (with stringified or symbolized keys)
def to_hash(options = {})
out = {}
keys.each do |k|
each_key do |k|
assignment_key = if options[:stringify_keys]
k.to_s
elsif options[:symbolize_keys]
@ -28,10 +28,10 @@ module Hashie
if self[k].is_a?(Array)
out[assignment_key] ||= []
self[k].each do |array_object|
out[assignment_key] << (Hash === array_object ? flexibly_convert_to_hash(array_object, options) : array_object)
out[assignment_key] << (array_object.is_a?(Hash) ? flexibly_convert_to_hash(array_object, options) : array_object)
end
else
out[assignment_key] = (Hash === self[k] || self[k].respond_to?(:to_hash)) ? flexibly_convert_to_hash(self[k], options) : self[k]
out[assignment_key] = self[k].is_a?(Hash) || self[k].respond_to?(:to_hash) ? flexibly_convert_to_hash(self[k], options) : self[k]
end
end
out
@ -45,7 +45,7 @@ module Hashie
private
def flexibly_convert_to_hash(object, options = {})
if object.method(:to_hash).arity == 0
if object.method(:to_hash).arity.zero?
object.to_hash
else
object.to_hash(options)

View File

@ -61,7 +61,7 @@ module Hashie
include Hashie::Extensions::PrettyInspect
include Hashie::Extensions::RubyVersionCheck
ALLOWED_SUFFIXES = %w(? ! = _)
ALLOWED_SUFFIXES = %w[? ! = _].freeze
class CannotDisableMashWarnings < StandardError
def initialize(message = 'You cannot disable warnings on the base Mash class. Please subclass the Mash and disable it in the subclass.')
@ -74,7 +74,7 @@ module Hashie
# @api semipublic
# @return [void]
def self.disable_warnings
fail CannotDisableMashWarnings if self == Hashie::Mash
raise CannotDisableMashWarnings if self == Hashie::Mash
@disable_warnings = true
end
@ -99,9 +99,9 @@ module Hashie
@_mashes ||= new
return @_mashes[path] if @_mashes.key?(path)
fail ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path)
raise ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path)
parser = options.fetch(:parser) { Hashie::Extensions::Parsers::YamlErbParser }
parser = options.fetch(:parser) { Hashie::Extensions::Parsers::YamlErbParser }
@_mashes[path] = new(parser.perform(path)).freeze
end
@ -114,7 +114,7 @@ module Hashie
end
end
alias_method :to_s, :inspect
alias to_s inspect
# If you pass in an existing hash, it will
# convert it to a Mash including recursively
@ -125,10 +125,10 @@ module Hashie
default ? super(default) : super(&blk)
end
class << self; alias_method :[], :new; end
class << self; alias [] new; end
alias_method :regular_reader, :[]
alias_method :regular_writer, :[]=
alias regular_reader []
alias regular_writer []=
# Retrieves an attribute set in the Mash. Will convert
# any key passed in to a string before retrieving.
@ -149,8 +149,8 @@ module Hashie
regular_writer(key, convert ? convert_value(value) : value)
end
alias_method :[], :custom_reader
alias_method :[]=, :custom_writer
alias [] custom_reader
alias []= custom_writer
# This is the bang method reader, it will return a new Mash
# if there isn't a value already assigned to the key requested.
@ -183,26 +183,26 @@ module Hashie
super(*keys.map { |key| convert_key(key) })
end
alias_method :regular_dup, :dup
alias regular_dup dup
# Duplicates the current mash as a new mash.
def dup
self.class.new(self, default, &default_proc)
end
alias_method :regular_key?, :key?
alias regular_key? key?
def key?(key)
super(convert_key(key))
end
alias_method :has_key?, :key?
alias_method :include?, :key?
alias_method :member?, :key?
alias has_key? key?
alias include? key?
alias member? key?
# Performs a deep_update on a duplicate of the
# current mash.
def deep_merge(other_hash, &blk)
dup.deep_update(other_hash, &blk)
end
alias_method :merge, :deep_merge
alias merge deep_merge
# Recursively merges this mash with the passed
# in hash, merging each hash in the hierarchy.
@ -213,15 +213,15 @@ module Hashie
custom_reader(key).deep_update(v, &blk)
else
value = convert_value(v, true)
value = convert_value(blk.call(key, self[k], value), true) if blk && self.key?(k)
value = convert_value(yield(key, self[k], value), true) if blk && key?(k)
custom_writer(key, value, false)
end
end
self
end
alias_method :deep_merge!, :deep_update
alias_method :update, :deep_update
alias_method :merge!, :update
alias deep_merge! deep_update
alias update deep_update
alias merge! update
# Assigns a value to a key
def assign_property(name, value)
@ -263,7 +263,7 @@ module Hashie
method_name.end_with?(*ALLOWED_SUFFIXES) && key?(method_name.chop)
end
def method_missing(method_name, *args, &blk)
def method_missing(method_name, *args, &blk) # rubocop:disable Style/MethodMissing
return self.[](method_name, &blk) if key?(method_name)
name, suffix = method_name_and_suffix(method_name)
case suffix

View File

@ -64,7 +64,7 @@ module Hashie
# Raise (or yield) unless something matches the key.
#
def fetch(*args)
fail ArgumentError, "Expected 1-2 arguments, got #{args.length}" \
raise ArgumentError, "Expected 1-2 arguments, got #{args.length}" \
unless (1..2).cover?(args.length)
key, default = args
@ -78,7 +78,7 @@ module Hashie
elsif default
default
else
fail KeyError, "key not found: #{key.inspect}"
raise KeyError, "key not found: #{key.inspect}"
end
end
@ -125,11 +125,11 @@ module Hashie
end
def method_missing(*args, &block)
@hash.send(*args, &block)
@hash.send(*args, &block) || super
end
def respond_to_missing?(*args)
@hash.respond_to?(*args)
def respond_to_missing?(method_name, _include_private = false)
@hash.respond_to?(method_name)
end
private

View File

@ -1,3 +1,3 @@
module Hashie
VERSION = '3.5.8'
VERSION = '3.5.8'.freeze
end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe Array do
with_minimum_ruby('2.3.0') do
describe '#dig' do
let(:array) { Hashie::Array.new([:a, :b, :c]) }
let(:array) { Hashie::Array.new(%i[a b c]) }
it 'works with a string index' do
expect(array.dig('0')).to eq(:a)

View File

@ -310,7 +310,7 @@ describe DashTest do
describe 'properties' do
it 'lists defined properties' do
expect(described_class.properties).to eq Set.new([:first_name, :email, :count])
expect(described_class.properties).to eq Set.new(%i[first_name email count])
end
it 'checks if a property exists' do
@ -348,7 +348,7 @@ describe DashTest do
end
it 'leaves only specified keys and keys with default values' do
expect(subject.keys.sort_by(&:to_s)).to eq [:count, :first_name]
expect(subject.keys.sort_by(&:to_s)).to eq %i[count first_name]
expect(subject.email).to be_nil
expect(subject.count).to eq 0
end

View File

@ -154,7 +154,7 @@ describe Hashie::Extensions::Coercion do
it 'supports coercion for Array' do
subject.coerce_key :foo, Array[Coercable]
instance[:foo] = %w('bar', 'bar2')
instance[:foo] = %w[bar bar2]
expect(instance[:foo]).to all(be_coerced)
expect(instance[:foo]).to be_a(Array)
end
@ -162,7 +162,7 @@ describe Hashie::Extensions::Coercion do
it 'supports coercion for Set' do
subject.coerce_key :foo, Set[Coercable]
instance[:foo] = Set.new(%w('bar', 'bar2'))
instance[:foo] = Set.new(%w[bar bar2])
expect(instance[:foo]).to all(be_coerced)
expect(instance[:foo]).to be_a(Set)
end
@ -170,7 +170,7 @@ describe Hashie::Extensions::Coercion do
it 'supports coercion for Set of primitive' do
subject.coerce_key :foo, Set[Initializable]
instance[:foo] = %w('bar', 'bar2')
instance[:foo] = %w[bar bar2]
expect(instance[:foo].map(&:value)).to all(eq 'String')
expect(instance[:foo]).to be_none(&:coerced?)
expect(instance[:foo]).to be_a(Set)
@ -558,18 +558,26 @@ describe Hashie::Extensions::Coercion do
end
it 'raises a CoercionError when coercion is not possible' do
type = if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum
end
type =
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum # rubocop:disable Lint/UnifiedInteger
end
subject.coerce_value type, Symbol
expect { instance[:hi] = 1 }.to raise_error(Hashie::CoercionError, /Cannot coerce property :hi from #{type} to Symbol/)
end
it 'coerces Integer to String' do
subject.coerce_value Integer, String
type =
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >= Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum # rubocop:disable Lint/UnifiedInteger
end
subject.coerce_value type, String
{
fixnum: 2,
@ -579,7 +587,7 @@ describe Hashie::Extensions::Coercion do
complex: Complex(1)
}.each do |k, v|
instance[k] = v
if v.is_a? Integer
if v.is_a? type
expect(instance[k]).to be_a(String)
expect(instance[k]).to eq(v.to_s)
else
@ -610,8 +618,8 @@ describe Hashie::Extensions::Coercion do
return !!(v =~ /^(true|t|yes|y|1)$/i)
end)
true_values = %w(true t yes y 1)
false_values = %w(false f no n 0)
true_values = %w[true t yes y 1]
false_values = %w[false f no n 0]
true_values.each do |v|
instance[:foo] = v

View File

@ -78,7 +78,7 @@ describe Hashie::Extensions::DeepLocate do
[
lambda do |_key, _value, object|
object.is_a?(Array) &&
!object.extend(described_class).deep_locate(:match).empty?
!object.extend(described_class).deep_locate(:match).empty?
end,
[
hash[:query][:bool][:must],

View File

@ -28,7 +28,7 @@ describe Hashie::Extensions::DeepMerge do
it 'merges new nested hash entries by value, not by reference' do
h1.deep_merge!(h2)
expect { h1[:e][:e1] = 'changed' }.not_to change { h2[:e][:e1] }
expect { h1[:e][:e1] = 'changed' }.not_to(change { h2[:e][:e1] })
end
end

View File

@ -6,7 +6,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :new
alias build new
end
end
@ -14,7 +14,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :[]
alias build []
end
end
@ -22,7 +22,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :try_convert
alias build try_convert
end
end
@ -44,7 +44,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
end.new
merged_hash = indifferent_hash.merge(:cat => 'meow')
merged_hash = indifferent_hash.merge(cat: 'meow')
expect(merged_hash[:cat]).to eq('meow')
expect(merged_hash['cat']).to eq('meow')
@ -70,7 +70,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
end.new
indifferent_hash.merge!(:cat => 'meow')
indifferent_hash[:cat] = 'meow'
expect(indifferent_hash[:cat]).to eq('meow')
expect(indifferent_hash['cat']).to eq('meow')
@ -126,7 +126,7 @@ describe Hashie::Extensions::IndifferentAccess do
describe '#values_at' do
it 'indifferently finds values' do
h = subject.build(:foo => 'bar', 'baz' => 'qux')
expect(h.values_at('foo', :baz)).to eq %w(bar qux)
expect(h.values_at('foo', :baz)).to eq %w[bar qux]
end
it 'returns the same instance of the hash that was set' do
@ -208,7 +208,7 @@ describe Hashie::Extensions::IndifferentAccess do
expect(h).to be_key('foo')
end
%w(include? member? has_key?).each do |key_alias|
%w[include? member? has_key?].each do |key_alias|
it "is aliased as #{key_alias}" do
expect(h.send(key_alias.to_sym, :foo)).to be(true)
expect(h.send(key_alias.to_sym, 'foo')).to be(true)

View File

@ -11,7 +11,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :new
alias build new
end
end
@ -19,7 +19,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :[]
alias build []
end
end
@ -27,7 +27,7 @@ describe Hashie::Extensions::IndifferentAccess do
include Hashie::Extensions::IndifferentAccess
class << self
alias_method :build, :try_convert
alias build try_convert
end
end
@ -54,7 +54,7 @@ describe Hashie::Extensions::IndifferentAccess do
:foo => 'bar', 'baz' => 'qux'
)
h = subject.build(indifferent_hash)
expect(h.values_at('foo', :baz)).to eq %w(bar qux)
expect(h.values_at('foo', :baz)).to eq %w[bar qux]
end
end
@ -91,7 +91,7 @@ describe Hashie::Extensions::IndifferentAccess do
expect(h).to be_key('foo')
end
%w(include? member? has_key?).each do |key_alias|
%w[include? member? has_key?].each do |key_alias|
it "is aliased as #{key_alias}" do
expect(h.send(key_alias.to_sym, :foo)).to be(true)
expect(h.send(key_alias.to_sym, 'foo')).to be(true)

View File

@ -20,7 +20,7 @@ describe Hashie::Extensions::MethodReader do
end
it 'reads nil and false values out properly' do
h = subject.new(nil: nil, false: false)
h = subject.new(nil: nil, false: false) # rubocop:disable Lint/BooleanSymbol
expect(h.nil).to eq nil
expect(h.false).to eq false
end
@ -168,13 +168,13 @@ describe Hashie::Extensions::MethodOverridingWriter do
end
it 'aliases the method with two leading underscores' do
expect(subject.__zip).to eq [[%w(zip a-dee-doo-dah)]]
expect(subject.__zip).to eq [[%w[zip a-dee-doo-dah]]]
end
it 'does not re-alias when overriding an already overridden method' do
subject.zip = 'test'
expect(subject.zip).to eq 'test'
expect(subject.__zip).to eq [[%w(zip test)]]
expect(subject.__zip).to eq [[%w[zip test]]]
end
end
end

View File

@ -14,7 +14,7 @@ shared_examples 'stringify_keys!' do
object[:abc] = 'abc'
object[123] = '123'
invoke :stringify_keys!
expect((object.keys & %w(abc 123)).size).to eq 2
expect((object.keys & %w[abc 123]).size).to eq 2
end
it 'converts nested instances of the same class' do
@ -53,7 +53,7 @@ shared_examples 'stringify_keys' do
object[:abc] = 'def'
copy = invoke :stringify_keys
expect(object.keys).to eq [:abc]
expect(copy.keys).to eq %w(abc)
expect(copy.keys).to eq %w[abc]
end
end
@ -71,7 +71,7 @@ describe Hashie::Extensions::StringifyKeys do
context 'class methods' do
subject { described_class }
let(:object) { Hash.new }
let(:object) { {} }
describe '.stringify_keys' do
include_examples 'stringify_keys'
@ -113,7 +113,7 @@ describe Hashie do
end
subject { described_class }
let(:object) { Hash.new }
let(:object) { {} }
describe '.stringify_keys' do
include_examples 'stringify_keys'

View File

@ -14,7 +14,7 @@ shared_examples 'symbolize_keys!' do
object['abc'] = 'abc'
object['def'] = 'def'
invoke :symbolize_keys!
expect((object.keys & [:abc, :def]).size).to eq 2
expect((object.keys & %i[abc def]).size).to eq 2
end
it 'converts nested instances of the same class' do
@ -76,7 +76,7 @@ describe Hashie::Extensions::SymbolizeKeys do
context 'class methods' do
subject { described_class }
let(:object) { Hash.new }
let(:object) { {} }
describe '.symbolize_keys' do
include_examples 'symbolize_keys'
@ -118,7 +118,7 @@ describe Hashie do
end
subject { described_class }
let(:object) { Hash.new }
let(:object) { {} }
describe '.symbolize_keys' do
include_examples 'symbolize_keys'

View File

@ -184,7 +184,8 @@ describe Hashie::Mash do
details: {
email: 'michael@asf.com',
address: 'Nowhere road'
})
}
)
end
describe '#deep_update' do
@ -284,7 +285,7 @@ describe Hashie::Mash do
end
it 'leaves only specified keys' do
expect(subject.keys.sort).to eq %w(details middle_name)
expect(subject.keys.sort).to eq %w[details middle_name]
expect(subject.first_name?).to be_falsy
expect(subject).not_to respond_to(:first_name)
expect(subject.last_name?).to be_falsy
@ -386,28 +387,28 @@ describe Hashie::Mash do
end
it 'responds to a set key with a suffix' do
%w(= ? ! _).each do |suffix|
%w[= ? ! _].each do |suffix|
expect(subject).to be_respond_to(:"abc#{suffix}")
end
end
it 'is able to access the suffixed key as a method' do
%w(= ? ! _).each do |suffix|
%w[= ? ! _].each do |suffix|
expect(subject.method(:"abc#{suffix}")).to_not be_nil
end
end
it 'responds to an unknown key with a suffix' do
%w(= ? ! _).each do |suffix|
%w[= ? ! _].each do |suffix|
expect(subject).to be_respond_to(:"xyz#{suffix}")
end
end
it 'is able to access an unknown suffixed key as a method' do
# See https://github.com/intridea/hashie/pull/285 for more information
pending_for(engine: 'ruby', versions: %w(2.2.0 2.2.1 2.2.2))
pending_for(engine: 'ruby', versions: %w[2.2.0 2.2.1 2.2.2])
%w(= ? ! _).each do |suffix|
%w[= ? ! _].each do |suffix|
expect(subject.method(:"xyz#{suffix}")).to_not be_nil
end
end
@ -560,7 +561,7 @@ describe Hashie::Mash do
end
it 'includes all keys' do
expect(mash.to_hash.keys).to eql(%w(outer testing))
expect(mash.to_hash.keys).to eql(%w[outer testing])
end
it 'converts keys to symbols when symbolize_keys option is true' do

View File

@ -4,12 +4,12 @@ describe Hashie::Extensions::Parsers::YamlErbParser do
describe '.perform' do
context 'a file' do
let(:config) do
<<-EOF
<<-CONFIG
---
foo: verbatim
bar: <%= "erb" %>
baz: "<%= __FILE__ %>"
EOF
CONFIG
end
let(:path) { 'template.yml' }
@ -36,7 +36,7 @@ baz: "<%= __FILE__ %>"
file
end
subject { described_class.new(Pathname tempfile.path) }
subject { described_class.new(Pathname(tempfile.path)) }
it '"#perform" can be done in case of path is a Pathname object.' do
expect(subject.perform).to eq 'foo' => 'hello'

View File

@ -10,7 +10,7 @@ describe Hashie::Rash do
1 => 'awesome',
1..1000 => 'rangey',
/(bcd)/ => proc { |m| m[1] }
# /.+/ => "EVERYTHING"
# /.+/ => "EVERYTHING"
)
end
@ -18,7 +18,7 @@ describe Hashie::Rash do
expect(subject['other']).to eq 'whee'
expect(subject['well hello there']).to eq 'hello'
expect(subject['the world is round']).to eq 'world'
expect(subject.all('hello world').sort).to eq %w(hello world)
expect(subject.all('hello world').sort).to eq %w[hello world]
end
it 'finds regexps' do

View File

@ -153,7 +153,7 @@ describe Hashie::Trash do
end
it 'maintains translations hash mapping from the original to the translated name' do
expect(SomeDataModel.translations).to eq(config: [:value_a, :value_b])
expect(SomeDataModel.translations).to eq(config: %i[value_a value_b])
end
end

View File

@ -19,7 +19,7 @@ module RailsApp
end
end
LAYOUT = <<-HTML
LAYOUT = <<-HTML.freeze
<!DOCTYPE html>
<html>
<head>
@ -32,7 +32,7 @@ LAYOUT = <<-HTML
</html>
HTML
INDEX = '<h1>Hello, world!</h1>'
INDEX = '<h1>Hello, world!</h1>'.freeze
class ApplicationController < ActionController::Base
include Rails.application.routes.url_helpers
@ -44,8 +44,7 @@ class ApplicationController < ActionController::Base
'application/index.html.erb' => INDEX
)]
def index
end
def index; end
end
Bundler.require(:default, Rails.env)

View File

@ -19,8 +19,8 @@ module OmniAuth
info do
{
:name => raw_info['name'],
:email => raw_info['email']
name: raw_info['name'],
email: raw_info['email']
}
end

View File

@ -3,7 +3,7 @@ source 'http://rubygems.org'
gem 'benchmark-ips'
gem 'hashie', path: '../../..'
gem 'omniauth', '~> 1.4.1'
gem 'sinatra'
gem 'rack-test', '~> 0.6.3'
gem 'rake'
gem 'rspec', '~> 3.5.0'
gem 'rack-test', '~> 0.6.3'
gem 'sinatra'

View File

@ -11,7 +11,7 @@ namespace :perf do
def call_app(path = ENV['GET_PATH'] || '/')
result = @app.get(path)
fail "Did not succeed #{result.body}" unless result.status == 200
raise "Did not succeed #{result.body}" unless result.status == 200
result
end
end

View File

@ -14,7 +14,7 @@ module RailsApp
end
end
LAYOUT = <<-HTML
LAYOUT = <<-HTML.freeze
<!DOCTYPE html>
<html>
<head>
@ -27,7 +27,7 @@ LAYOUT = <<-HTML
</html>
HTML
INDEX = '<h1>Hello, world!</h1>'
INDEX = '<h1>Hello, world!</h1>'.freeze
class ApplicationController < ActionController::Base
include Rails.application.routes.url_helpers
@ -39,8 +39,7 @@ class ApplicationController < ActionController::Base
'application/index.html.erb' => INDEX
)]
def index
end
def index; end
end
Bundler.require(:default, Rails.env)