Commit Graph

26 Commits

Author SHA1 Message Date
kenner kliemann 792714b91c Add hash slice using IndifferentAccess. 2020-10-03 08:57:17 -04:00
Bobby McDonald 6a96527384
Change rubocop to allow 100 character lines.
For accessibility reasons, we should limit our lines to 100 chars max.
https://github.com/slack-ruby/slack-ruby-client/pull/293#discussion_r309472083
2019-10-17 23:55:45 -04:00
Bobby McDonald 1a30427c9d Allow mash error silencing (#488) 2019-10-14 14:14:47 -04:00
Bobby McDonald ca3604516b Make Hashie play nice with Rails 6 Hash#except method (#479) 2019-10-02 10:48:19 -04:00
Bobby McDonald 3e64a4f58d
Implement non-destructive hash methods
When calling the following non-destructive hash methods:
:compact
:invert
:reject
:select
:slice
:transform_keys
:transform_values
we would be returned an instance of a standard Hash rather
than a Mash (or subclass). This changes that behavior to
instead return an instance of the class the method was
called on.
2019-08-14 12:31:10 -04:00
Bobby McDonald f0faaca6ac Add selective key-conflict warnings for Mash subclasses (#478)
In some cases, you want to be able to ignore Mash warnings for keys
that you know you aren't going to access via a method accessor, yet be
warned for other keys that you know you might want to access. This
change adds the ability to selectively ignore warnings for specific keys
instead of globally ignoring the warnings.

The change retains the original behavior as well, so if you call
`Mash.disable_warnings` without a value it will still globally ignore
the warnings.
2019-07-18 12:11:40 -05:00
Daniel Doubrovkine (dB.) @dblockdotorg 30ab2a3cb0 Allow options on Mash.load (#474)
`Mash.load` uses the Ruby standard library to load Yaml-serialized files
into a Mash. The original implementation used `YAML.load` for this
purpose. However, that method is inherently unsafe so we switched to
using `YAML.safe_load`.

Safely loading Yaml files has many different domain-specific
configuration flags that we did not, by default, expose. This change
introduces the ability to configure the safe loading of Yaml files so
that all types of Yaml can be loaded when necessary using the flags from
the standard library.

This implementation preserves the backwards-compatibility with the prior
implementation so that it should not require updates from users of the
current `Mash.load` behavior. For those who this change affects, we
included upgrading documentation to ease the transition.
2019-03-22 14:04:22 -05:00
Vladimir Kochnev 250f174f48 Add Hashie::Extensions::Mash::DefineAccessors.
This patch adds an extension for Mash that makes it behave like
`OpenStruct`. It reduces overhead of `method_missing?` magic which is a
good thing! It's inspired by the recent @sferik's work on `OpenStruct` —
https://github.com/ruby/ruby/pull/1033.

When using it in `Mash` subclasses it makes them *remember* methods so
then it's more like `ActiveModel` than `OpenStruct` in this case.

To use it like `OpenStruct` one could use this shortcut:

```ruby
{ foo: 1, bar: 2 }.to_mash.with_accessors!
```

Implementation details:

It injects to class an anonymous module that stores accessor method
definitions. This is inspired by `ActiveModel` / `ActiveRecord`. It
allows to override accessors in subclass and call them via `super` if
this is intended.
2019-01-28 21:14:08 +03:00
Michael Herold 5b5ed2119d
[rubocop] Improve our RuboCop setup
Disable Metrics/BlockLength in specs because the length of a block in
the test suite isn't something we want to lint. We want the tests to be
as long as they need to be.

Set an explicit line length metric instead of continually updating this
as we go. Let's pick a max line length that we want to see and stick
with it. This metric should only ever decrease: we don't want to see it
ever increase again.
2018-09-30 14:59:58 -05:00
Michael Herold 6992fd1327
Update Rubocop todo 2018-08-14 21:37:47 -05:00
Michael Herold 91a5153fa3
Make Dash greedier when creating getters
Dash, in its current form, was created to be very conservative in
creating the getters for its properties. It only creates them when the
accompanying setter has not already been created. This means that the
property translation capability that is layered on top of Dash to create
a Trash cannot have dependence between properties in an
order-independent way.

This change makes it so Dash now greedily creates a getter method for
each property. To ensure that we don't do this more than once for
a given Dash class, we track the getters we have previously created.
This keeps the number of warnings from Ruby down to the same number of
warnings that were emitted prior to this change.

Given that Dash users expect the getter to be set, this doesn't feel
like it should cause any backwards-compatibility issues.
2018-08-11 15:53:58 -05:00
Michael Herold 5a6ffc7e2d
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.
2018-06-17 11:04:56 -05:00
Michael Herold a82c594710
Ensure IndifferentAccess is injected after merge
During non-destructive merges (i.e. `#merge`), the `IndifferentAccess` mixin was
failing to inject itself into the resulting Hash. This caused a `NoMethodError`
to be thrown when attempting to perform the action.

Now, we properly inject the mixin when necessary so the `#merge` method works.
2018-02-05 10:58:26 -06:00
Michael Herold 55cfb8adbc
Don't log when overwriting Mash keys
When we switched to using `#respond_to?` to detecting whether to log
a Mash collision, we started reporting when we were overwriting keys
that already exist in the Mash. This is a poor experience because it
causes extra warnings (as in #414) or, in the worst case, causes an
"undefined method" error (as in #413).

This change fixes that problem and benchmarks to ensure we're not
appreciably regressing performance. The results of two benchmarks are
below:

```
bundle exec ruby benchmark/mash_method_access.rb:

Warming up --------------------------------------
  before    92.456k i/100ms
Calculating -------------------------------------
  before      1.290M (± 4.4%) i/s -      6.472M in   5.028183s

Pausing here -- run Ruby again to measure the next benchmark...

Warming up --------------------------------------
    after    92.941k i/100ms
Calculating -------------------------------------
    after      1.326M (± 5.4%) i/s -      6.692M in   5.060756s

Comparison:
   after:  1326239.2 i/s
  before:  1289624.0 i/s - same-ish: difference falls within error
```

and

```
within spec/integrations/omniauth,
bundle exec rake perf:ips

Warming up --------------------------------------
  before     1.260k i/100ms
Calculating -------------------------------------
  before     13.114k (± 4.2%) i/s -     66.780k in   5.101689s

Pausing here -- run Ruby again to measure the next benchmark...

Warming up --------------------------------------
    after     1.299k i/100ms
Calculating -------------------------------------
    after     13.149k (± 4.0%) i/s -     66.249k in   5.046630s

Comparison:
   after:    13148.9 i/s
  before:    13113.8 i/s - same-ish: difference falls within error
```

Closes #413
Closes #414
2017-02-24 07:47:52 -06:00
Michael Herold c071e4f9fd Add an extension to maintain original Mash keys (#326)
One of the behaviors of Mash that we see regularly surprise users is
that Mash stringifies any keys passed into it. This leads to unexpected
lack of synergy between Mash and its cousins (particularly Dash), since
the property DSLs do not handle indifferent key access.

This extension ensures that the original keys are kept inside the Mash's
data structure, at the expense of more costly logic for fetching
information indifferently. I have included a benchmark that compares the
two. The benchmark shows that when you are passing string keys into a
Mash, using this extension will actually be _faster_ than the default
implementation, but that the reverse is true when passing symbol keys.

In #296, I tried to do this universally for all Mashes, which slowed
down the fetching behavior for Mash significantly. I like this attempt
much better because it allows users to opt into the new behavior if they
want it, while still keeping the default implementation as-is.

Fixes #196 by giving the option of keeping the original structure of the
Mash when using it with Dash.

Fixes #246 by giving the option of opting into keeping the original
keys.

Closes #296 by giving a more flexible path forward that doesn't change
the semantics of the main Mash class.
2017-02-22 19:37:07 -06:00
Michael Herold 9636f68264 Carry over disabling warnings to subclasses 2017-02-10 19:36:20 -06:00
Michael Herold b2f94a4866 Allow Mash subclasses to disable warnings
Since we are transitively used as a dependency in many projects, we
should have given the ability to toggle this behavior off. The logging
feature is more of a "help people get started with Mash" feature. If
you're using Hashie in a library, it's likely that you already know the
tradeoffs of attempting to override methods on the object.

To use this feature, you only have to subclass Mash and then call the
class method:

```ruby
class KeyStore < Hashie::Mash
  disable_warnings
end
```
2017-02-04 14:38:00 -06:00
Michael Herold e35e628ddd Add a logging layer to address common issues (#381) 2016-11-02 06:47:33 -04:00
jonathan schatz fa524096f3 Fix support for Array#dig 2016-06-01 14:53:29 -07:00
Takashi Kokubun 1433295e22 Convert Mash keys for #dig 2016-02-08 09:26:51 +09:00
dblock 9298241eb2 Fix: broken cop, for now disabling hash syntax check. 2015-10-25 15:28:56 -04:00
dblock acc3d48b91 Upgraded to RuboCop 0.34.2. 2015-10-25 15:22:45 -04:00
Max Goldstein 62281bca63 Add Hashie::Mash#reverse_merge. Increase Rubocop class length.
Fixes intridea/hashie#270
2015-02-25 17:36:08 -05:00
Ryan Buckley 86a141598f add Hashie::Mash#extractable_options? 2015-01-19 12:16:11 -08:00
dblock dab7dc54cf Upgraded RuboCop to 0.28.0. 2014-12-30 16:07:47 -05:00
dblock 5e9a4c8e3b Locked version of RuboCop. 2014-11-18 09:38:46 -05:00