hashie 3.5.7 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +240 -164
- data/CONTRIBUTING.md +13 -6
- data/README.md +210 -29
- data/Rakefile +2 -2
- data/UPGRADING.md +83 -7
- data/hashie.gemspec +13 -7
- data/lib/hashie.rb +21 -19
- data/lib/hashie/clash.rb +12 -1
- data/lib/hashie/dash.rb +42 -21
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/coercion.rb +26 -19
- data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
- data/lib/hashie/extensions/dash/property_translation.rb +54 -28
- data/lib/hashie/extensions/deep_fetch.rb +5 -3
- data/lib/hashie/extensions/deep_find.rb +14 -5
- data/lib/hashie/extensions/deep_locate.rb +22 -8
- data/lib/hashie/extensions/deep_merge.rb +26 -10
- data/lib/hashie/extensions/indifferent_access.rb +8 -8
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +4 -5
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/mash/symbolize_keys.rb +1 -1
- data/lib/hashie/extensions/method_access.rb +47 -14
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +28 -4
- data/lib/hashie/extensions/ruby_version_check.rb +5 -1
- data/lib/hashie/extensions/strict_key_access.rb +16 -13
- data/lib/hashie/extensions/stringify_keys.rb +1 -1
- data/lib/hashie/extensions/symbolize_keys.rb +1 -1
- data/lib/hashie/hash.rb +18 -11
- data/lib/hashie/mash.rb +131 -70
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +6 -6
- data/lib/hashie/utils.rb +28 -0
- data/lib/hashie/version.rb +1 -1
- metadata +19 -128
- data/spec/hashie/array_spec.rb +0 -29
- data/spec/hashie/clash_spec.rb +0 -70
- data/spec/hashie/dash_spec.rb +0 -573
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -631
- data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
- data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
- data/spec/hashie/extensions/deep_find_spec.rb +0 -138
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -282
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
- data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
- data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
- data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -188
- data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
- data/spec/hashie/hash_spec.rb +0 -84
- data/spec/hashie/mash_spec.rb +0 -763
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
- data/spec/hashie/rash_spec.rb +0 -83
- data/spec/hashie/trash_spec.rb +0 -268
- data/spec/hashie/utils_spec.rb +0 -25
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/hashie_spec.rb +0 -13
- data/spec/integration/omniauth-oauth2/app.rb +0 -53
- data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
- data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
- data/spec/integration/omniauth/app.rb +0 -11
- data/spec/integration/omniauth/integration_spec.rb +0 -38
- data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
- data/spec/integration/rails/app.rb +0 -48
- data/spec/integration/rails/integration_spec.rb +0 -26
- data/spec/spec_helper.rb +0 -23
- data/spec/support/integration_specs.rb +0 -36
- data/spec/support/logger.rb +0 -24
- data/spec/support/module_context.rb +0 -11
- data/spec/support/ruby_version_check.rb +0 -6
data/CONTRIBUTING.md
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
Contributing to Hashie
|
2
2
|
======================
|
3
3
|
|
4
|
-
Hashie is work of [many contributors](https://github.com/
|
4
|
+
Hashie is work of [many contributors](https://github.com/hashie/hashie/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/hashie/hashie/pulls), [propose features and discuss issues](https://github.com/hashie/hashie/issues).
|
5
5
|
|
6
6
|
#### Fork the Project
|
7
7
|
|
8
|
-
Fork the [project on Github](https://github.com/
|
8
|
+
Fork the [project on Github](https://github.com/hashie/hashie) and check out your copy.
|
9
9
|
|
10
10
|
```
|
11
11
|
git clone https://github.com/contributor/hashie.git
|
12
12
|
cd hashie
|
13
|
-
git remote add upstream https://github.com/
|
13
|
+
git remote add upstream https://github.com/hashie/hashie.git
|
14
14
|
```
|
15
15
|
|
16
16
|
#### Create a Topic Branch
|
@@ -23,12 +23,19 @@ git pull upstream master
|
|
23
23
|
git checkout -b my-feature-branch
|
24
24
|
```
|
25
25
|
|
26
|
-
####
|
26
|
+
#### Install dependencies
|
27
|
+
|
28
|
+
You can use the setup script to install dependencies for the gem and its integration tests.
|
29
|
+
|
30
|
+
```
|
31
|
+
bin/setup
|
32
|
+
```
|
33
|
+
|
34
|
+
#### Test
|
27
35
|
|
28
36
|
Ensure that you can build the project and run tests.
|
29
37
|
|
30
38
|
```
|
31
|
-
bundle install
|
32
39
|
bundle exec rake
|
33
40
|
```
|
34
41
|
|
@@ -105,7 +112,7 @@ git push origin my-feature-branch -f
|
|
105
112
|
Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows.
|
106
113
|
|
107
114
|
```
|
108
|
-
* [#123](https://github.com/
|
115
|
+
* [#123](https://github.com/hashie/hashie/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
|
109
116
|
```
|
110
117
|
|
111
118
|
Amend your previous commit and force push the changes.
|
data/README.md
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# Hashie
|
2
2
|
|
3
|
-
[![Join the chat at https://gitter.im/
|
4
|
-
|
3
|
+
[![Join the chat at https://gitter.im/hashie/hashie](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hashie/hashie?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
5
4
|
[![Gem Version](http://img.shields.io/gem/v/hashie.svg)](http://badge.fury.io/rb/hashie)
|
6
|
-
[![Build Status](http://img.shields.io/travis/
|
7
|
-
[![
|
8
|
-
[![
|
9
|
-
[![Coverage Status](https://codeclimate.com/github/intridea/hashie/badges/coverage.svg)](https://codeclimate.com/github/intridea/hashie)
|
5
|
+
[![Build Status](http://img.shields.io/travis/hashie/hashie.svg)](https://travis-ci.org/hashie/hashie)
|
6
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/7a0b42c8a22c945571fd/test_coverage)](https://codeclimate.com/github/hashie/hashie/test_coverage)
|
7
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/7a0b42c8a22c945571fd/maintainability)](https://codeclimate.com/github/hashie/hashie/maintainability)
|
10
8
|
|
11
9
|
Hashie is a growing collection of tools that extend Hashes and make them more useful.
|
12
10
|
|
@@ -18,9 +16,9 @@ Hashie is available as a RubyGem:
|
|
18
16
|
$ gem install hashie
|
19
17
|
```
|
20
18
|
|
21
|
-
##
|
19
|
+
## Stable Release
|
22
20
|
|
23
|
-
You're reading the documentation for the stable release of Hashie,
|
21
|
+
You're reading the documentation for the stable release of Hashie, 4.1.0.(https://github.com/hashie/hashie/blob/v4.1.0/README.md).
|
24
22
|
|
25
23
|
## Hash Extensions
|
26
24
|
|
@@ -133,7 +131,7 @@ You can also use coerce from the following supertypes with `coerce_value`:
|
|
133
131
|
- Integer
|
134
132
|
- Numeric
|
135
133
|
|
136
|
-
Hashie does not have built-in support for
|
134
|
+
Hashie does not have built-in support for coercing boolean values, since Ruby does not have a built-in boolean type or standard method for coercing to a boolean. You can coerce to booleans using a custom proc.
|
137
135
|
|
138
136
|
### Coercion Proc
|
139
137
|
|
@@ -192,7 +190,7 @@ end
|
|
192
190
|
|
193
191
|
### KeyConversion
|
194
192
|
|
195
|
-
The KeyConversion extension gives you the convenience methods of `symbolize_keys` and `stringify_keys` along with their bang counterparts. You can also include just stringify or just symbolize with `Hashie::Extensions::StringifyKeys` or `Hashie::Extensions::SymbolizeKeys
|
193
|
+
The KeyConversion extension gives you the convenience methods of `symbolize_keys` and `stringify_keys` along with their bang counterparts. You can also include just stringify or just symbolize with `Hashie::Extensions::StringifyKeys` or [`Hashie::Extensions::SymbolizeKeys`](#mash-extension-symbolizekeys).
|
196
194
|
|
197
195
|
Hashie also has a utility method for converting keys on a Hash without a mixin:
|
198
196
|
|
@@ -245,6 +243,26 @@ overriding.zip #=> 'a-dee-doo-dah'
|
|
245
243
|
overriding.__zip #=> [[['zip', 'a-dee-doo-dah']]]
|
246
244
|
```
|
247
245
|
|
246
|
+
### MethodOverridingInitializer
|
247
|
+
|
248
|
+
The MethodOverridingInitializer extension will override hash methods if you pass in a normal hash to the constructor. It aliases any overridden method with two leading underscores. To include only this initializing functionality, you can include the single module `Hashie::Extensions::MethodOverridingInitializer`.
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
class MyHash < Hash
|
252
|
+
end
|
253
|
+
|
254
|
+
class MyOverridingHash < Hash
|
255
|
+
include Hashie::Extensions::MethodOverridingInitializer
|
256
|
+
end
|
257
|
+
|
258
|
+
non_overriding = MyHash.new(zip: 'a-dee-doo-dah')
|
259
|
+
non_overriding.zip #=> []
|
260
|
+
|
261
|
+
overriding = MyOverridingHash.new(zip: 'a-dee-doo-dah')
|
262
|
+
overriding.zip #=> 'a-dee-doo-dah'
|
263
|
+
overriding.__zip #=> [[['zip', 'a-dee-doo-dah']]]
|
264
|
+
```
|
265
|
+
|
248
266
|
### IndifferentAccess
|
249
267
|
|
250
268
|
This extension can be mixed in to your Hash subclass to allow you to use Strings or Symbols interchangeably as keys; similar to the `params` hash in Rails.
|
@@ -298,8 +316,8 @@ p.email # => NoMethodError
|
|
298
316
|
|
299
317
|
### DeepMerge
|
300
318
|
|
301
|
-
This extension
|
302
|
-
system
|
319
|
+
This extension allows you to easily include a recursive merging
|
320
|
+
system into any Hash descendant:
|
303
321
|
|
304
322
|
```ruby
|
305
323
|
class MyHash < Hash
|
@@ -470,9 +488,11 @@ mash.inspect # => <Hashie::Mash>
|
|
470
488
|
|
471
489
|
**Note:** The `?` method will return false if a key has been set to false or nil. In order to check if a key has been set at all, use the `mash.key?('some_key')` method instead.
|
472
490
|
|
491
|
+
### How does Mash handle conflicts with pre-existing methods?
|
492
|
+
|
473
493
|
Please note that a Mash will not override methods through the use of the property-like syntax. This can lead to confusion if you expect to be able to access a Mash value through the property-like syntax for a key that conflicts with a method name. However, it protects users of your library from the unexpected behavior of those methods being overridden behind the scenes.
|
474
494
|
|
475
|
-
|
495
|
+
#### Example:
|
476
496
|
|
477
497
|
```ruby
|
478
498
|
mash = Hashie::Mash.new
|
@@ -481,9 +501,89 @@ mash.zip = "Method Override?"
|
|
481
501
|
mash.zip # => [[["name", "My Mash"]], [["zip", "Method Override?"]]]
|
482
502
|
```
|
483
503
|
|
504
|
+
Since Mash gives you the ability to set arbitrary keys that then act as methods, Hashie logs when there is a conflict between a key and a pre-existing method. You can set the logger that this logs message to via the global Hashie logger:
|
505
|
+
|
506
|
+
```ruby
|
507
|
+
Hashie.logger = Rails.logger
|
508
|
+
```
|
509
|
+
|
510
|
+
You can also disable the logging in subclasses of Mash:
|
511
|
+
|
512
|
+
```ruby
|
513
|
+
class Response < Hashie::Mash
|
514
|
+
disable_warnings
|
515
|
+
end
|
516
|
+
```
|
517
|
+
|
518
|
+
The default is to disable logging for all methods that conflict. If you would like to only disable the logging for specific methods, you can include an array of method keys:
|
519
|
+
|
520
|
+
```ruby
|
521
|
+
class Response < Hashie::Mash
|
522
|
+
disable_warnings :zip, :zap
|
523
|
+
end
|
524
|
+
```
|
525
|
+
|
526
|
+
This behavior is cumulative. The examples above and below behave identically.
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
class Response < Hashie::Mash
|
530
|
+
disable_warnings :zip
|
531
|
+
disable_warnings :zap
|
532
|
+
end
|
533
|
+
```
|
534
|
+
|
535
|
+
Disable warnings will honor the last `disable_warnings` call. Calling without parameters will override the ignored methods list, and calling with parameters will create a new ignored methods list. This includes child classes that inherit from a class that disables warnings.
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
class Message < Hashie::Mash
|
539
|
+
disable_warnings :zip, :zap
|
540
|
+
disable_warnings
|
541
|
+
end
|
542
|
+
|
543
|
+
# No errors will be logged
|
544
|
+
Message.new(merge: 'true', compact: true)
|
545
|
+
```
|
546
|
+
|
547
|
+
```ruby
|
548
|
+
class Message < Hashie::Mash
|
549
|
+
disable_warnings
|
550
|
+
end
|
551
|
+
|
552
|
+
class Response < Message
|
553
|
+
disable_warnings :zip, :zap
|
554
|
+
end
|
555
|
+
|
556
|
+
# 2 errors will be logged
|
557
|
+
Response.new(merge: 'true', compact: true, zip: '90210', zap: 'electric')
|
558
|
+
```
|
559
|
+
|
560
|
+
If you would like to create an anonymous subclass of a Hashie::Mash with key conflict warnings disabled:
|
561
|
+
|
562
|
+
```ruby
|
563
|
+
Hashie::Mash.quiet.new(zip: '90210', compact: true) # no errors logged
|
564
|
+
Hashie::Mash.quiet(:zip).new(zip: '90210', compact: true) # error logged for compact
|
565
|
+
```
|
566
|
+
|
567
|
+
### How does the wrapping of Mash sub-Hashes work?
|
568
|
+
|
569
|
+
Mash duplicates any sub-Hashes that you add to it and wraps them in a Mash. This allows for infinite chaining of nested Hashes within a Mash without modifying the object(s) that are passed into the Mash. When you subclass Mash, the subclass wraps any sub-Hashes in its own class. This preserves any extensions that you mixed into the Mash subclass and allows them to work within the sub-Hashes, in addition to the main containing Mash.
|
570
|
+
|
571
|
+
#### Example:
|
572
|
+
|
573
|
+
```ruby
|
574
|
+
mash = Hashie::Mash.new(name: "Hashie", dependencies: { rake: "< 11", rspec: "~> 3.0" })
|
575
|
+
mash.dependencies.class #=> Hashie::Mash
|
576
|
+
|
577
|
+
class MyGem < Hashie::Mash; end
|
578
|
+
my_gem = MyGem.new(name: "Hashie", dependencies: { rake: "< 11", rspec: "~> 3.0" })
|
579
|
+
my_gem.dependencies.class #=> MyGem
|
580
|
+
```
|
581
|
+
|
582
|
+
### What else can Mash do?
|
583
|
+
|
484
584
|
Mash allows you also to transform any files into a Mash objects.
|
485
585
|
|
486
|
-
|
586
|
+
#### Example:
|
487
587
|
|
488
588
|
```yml
|
489
589
|
#/etc/config/settings/twitter.yml
|
@@ -515,7 +615,7 @@ Twitter.extend mash.to_module # NOTE: if you want another name than settings, ca
|
|
515
615
|
Twitter.settings.api_key # => 'abcd'
|
516
616
|
```
|
517
617
|
|
518
|
-
You can use another parser (by default: YamlErbParser):
|
618
|
+
You can use another parser (by default: [YamlErbParser](lib/hashie/extensions/parsers/yaml_erb_parser.rb)):
|
519
619
|
|
520
620
|
```
|
521
621
|
#/etc/data/user.csv
|
@@ -531,18 +631,12 @@ mash = Mash.load('data/user.csv', parser: MyCustomCsvParser)
|
|
531
631
|
mash[1] #=> { name: 'John', lastname: 'Doe' }
|
532
632
|
```
|
533
633
|
|
534
|
-
|
634
|
+
The `Mash#load` method calls `YAML.safe_load(path, [], [], true)`.
|
535
635
|
|
536
|
-
|
537
|
-
Hashie.logger = Rails.logger
|
538
|
-
```
|
539
|
-
|
540
|
-
You can also disable the logging in subclasses of Mash:
|
636
|
+
Specify `permitted_symbols`, `permitted_classes` and `aliases` options as needed.
|
541
637
|
|
542
638
|
```ruby
|
543
|
-
|
544
|
-
disable_warnings
|
545
|
-
end
|
639
|
+
Mash.load('data/user.csv', permitted_classes: [Symbol], permitted_symbols: [], aliases: false)
|
546
640
|
```
|
547
641
|
|
548
642
|
### Mash Extension: KeepOriginalKeys
|
@@ -564,6 +658,30 @@ mash['string_key'] #=> 'string'
|
|
564
658
|
mash[:string_key] #=> 'string'
|
565
659
|
```
|
566
660
|
|
661
|
+
### Mash Extension: PermissiveRespondTo
|
662
|
+
|
663
|
+
By default, Mash only states that it responds to built-in methods, affixed methods (e.g. setters, underbangs, etc.), and keys that it currently contains. That means it won't state that it responds to a getter for an unset key, as in the following example:
|
664
|
+
|
665
|
+
```ruby
|
666
|
+
mash = Hashie::Mash.new(a: 1)
|
667
|
+
mash.respond_to? :b #=> false
|
668
|
+
```
|
669
|
+
|
670
|
+
This means that by default Mash is not a perfect match for use with a SimpleDelegator since the delegator will not forward messages for unset keys to the Mash even though it can handle them.
|
671
|
+
|
672
|
+
In order to have a SimpleDelegator-compatible Mash, you can use the `PermissiveRespondTo` extension to make Mash respond to anything.
|
673
|
+
|
674
|
+
```ruby
|
675
|
+
class PermissiveMash < Hashie::Mash
|
676
|
+
include Hashie::Extensions::Mash::PermissiveRespondTo
|
677
|
+
end
|
678
|
+
|
679
|
+
mash = PermissiveMash.new(a: 1)
|
680
|
+
mash.respond_to? :b #=> true
|
681
|
+
```
|
682
|
+
|
683
|
+
This comes at the cost of approximately 20% performance for initialization and setters and 19KB of permanent memory growth for each such class that you create.
|
684
|
+
|
567
685
|
### Mash Extension: SafeAssignment
|
568
686
|
|
569
687
|
This extension can be mixed into a Mash to guard the attempted overwriting of methods by property setters. When mixed in, the Mash will raise an `ArgumentError` if you attempt to write a property with the same name as an existing method.
|
@@ -580,9 +698,9 @@ safe_mash.zip = 'Test' # => ArgumentError
|
|
580
698
|
safe_mash[:zip] = 'test' # => still ArgumentError
|
581
699
|
```
|
582
700
|
|
583
|
-
### Mash Extension
|
701
|
+
### Mash Extension: SymbolizeKeys
|
584
702
|
|
585
|
-
This extension can be mixed into a Mash to change the default behavior of converting keys to strings. After mixing this extension into a Mash, the Mash will convert all keys to symbols.
|
703
|
+
This extension can be mixed into a Mash to change the default behavior of converting keys to strings. After mixing this extension into a Mash, the Mash will convert all keys to symbols. It can be useful to use with keywords argument, which required symbol keys.
|
586
704
|
|
587
705
|
```ruby
|
588
706
|
class SymbolizedMash < ::Hashie::Mash
|
@@ -593,6 +711,12 @@ symbol_mash = SymbolizedMash.new
|
|
593
711
|
symbol_mash['test'] = 'value'
|
594
712
|
symbol_mash.test #=> 'value'
|
595
713
|
symbol_mash.to_h #=> {test: 'value'}
|
714
|
+
|
715
|
+
def example(test:)
|
716
|
+
puts test
|
717
|
+
end
|
718
|
+
|
719
|
+
example(symbol_mash) #=> value
|
596
720
|
```
|
597
721
|
|
598
722
|
There is a major benefit and coupled with a major trade-off to this decision (at least on older Rubies). As a benefit, by using symbols as keys, you will be able to use the implicit conversion of a Mash via the `#to_hash` method to destructure (or splat) the contents of a Mash out to a block. This can be handy for doing iterations through the Mash's keys and values, as follows:
|
@@ -607,6 +731,31 @@ end
|
|
607
731
|
|
608
732
|
However, on Rubies less than 2.0, this means that every key you send to the Mash will generate a symbol. Since symbols are not garbage-collected on older versions of Ruby, this can cause a slow memory leak when using a symbolized Mash with data generated from user input.
|
609
733
|
|
734
|
+
### Mash Extension: DefineAccessors
|
735
|
+
|
736
|
+
This extension can be mixed into a Mash so it makes it behave like `OpenStruct`. It reduces the overhead of `method_missing?` magic by lazily defining field accessors when they're requested.
|
737
|
+
|
738
|
+
```ruby
|
739
|
+
class MyHash < ::Hashie::Mash
|
740
|
+
include Hashie::Extensions::Mash::DefineAccessors
|
741
|
+
end
|
742
|
+
|
743
|
+
mash = MyHash.new
|
744
|
+
MyHash.method_defined?(:foo=) #=> false
|
745
|
+
mash.foo = 123
|
746
|
+
MyHash.method_defined?(:foo=) #=> true
|
747
|
+
|
748
|
+
MyHash.method_defined?(:foo) #=> false
|
749
|
+
mash.foo #=> 123
|
750
|
+
MyHash.method_defined?(:foo) #=> true
|
751
|
+
```
|
752
|
+
|
753
|
+
You can also extend the existing mash without defining a class:
|
754
|
+
|
755
|
+
```ruby
|
756
|
+
mash = ::Hashie::Mash.new.with_accessors!
|
757
|
+
```
|
758
|
+
|
610
759
|
## Dash
|
611
760
|
|
612
761
|
Dash is an extended Hash that has a discrete set of defined properties and only those properties may be set on the hash. Additionally, you can set defaults for each property. You can also flag a property as required. Required properties will raise an exception if unset. Another option is message for required properties, which allow you to add custom messages for required property.
|
@@ -676,6 +825,38 @@ p = Tricky.new('trick' => 'two')
|
|
676
825
|
p.trick # => NoMethodError
|
677
826
|
```
|
678
827
|
|
828
|
+
### Potential gotchas
|
829
|
+
|
830
|
+
Because Dashes are subclasses of the built-in Ruby Hash class, the double-splat operator takes the Dash as-is without any conversion. This can lead to strange behavior when you use the double-splat operator on a Dash as the first part of a keyword list or built Hash. For example:
|
831
|
+
|
832
|
+
```ruby
|
833
|
+
class Foo < Hashie::Dash
|
834
|
+
property :bar
|
835
|
+
end
|
836
|
+
|
837
|
+
foo = Foo.new(bar: 'baz') #=> {:bar=>"baz"}
|
838
|
+
qux = { **foo, quux: 'corge' } #=> {:bar=> "baz", :quux=>"corge"}
|
839
|
+
qux.is_a?(Foo) #=> true
|
840
|
+
qux[:quux]
|
841
|
+
#=> raise NoMethodError, "The property 'quux' is not defined for Foo."
|
842
|
+
qux.key?(:quux) #=> true
|
843
|
+
```
|
844
|
+
|
845
|
+
You can work around this problem in two ways:
|
846
|
+
|
847
|
+
1. Call `#to_h` on the resulting object to convert it into a Hash.
|
848
|
+
2. Use the double-splat operator on the Dash as the last argument in the Hash literal. This will cause the resulting object to be a Hash instead of a Dash, thereby circumventing the problem.
|
849
|
+
|
850
|
+
```ruby
|
851
|
+
qux = { **foo, quux: 'corge' }.to_h #=> {:bar=> "baz", :quux=>"corge"}
|
852
|
+
qux.is_a?(Hash) #=> true
|
853
|
+
qux[:quux] #=> "corge"
|
854
|
+
|
855
|
+
qux = { quux: 'corge', **foo } #=> {:quux=>"corge", :bar=> "baz"}
|
856
|
+
qux.is_a?(Hash) #=> true
|
857
|
+
qux[:quux] #=> "corge"
|
858
|
+
```
|
859
|
+
|
679
860
|
### Dash Extension: PropertyTranslation
|
680
861
|
|
681
862
|
The `Hashie::Extensions::Dash::PropertyTranslation` mixin extends a Dash with
|
@@ -716,7 +897,7 @@ class DataModelHash < Hashie::Dash
|
|
716
897
|
end
|
717
898
|
|
718
899
|
model = DataModelHash.new(id: '123', created: '2014-04-25 22:35:28')
|
719
|
-
model.id.class #=> Fixnum
|
900
|
+
model.id.class #=> Integer (Fixnum if you are using Ruby 2.3 or lower)
|
720
901
|
model.created_at.class #=> Time
|
721
902
|
```
|
722
903
|
|
@@ -785,7 +966,7 @@ this will produce the following
|
|
785
966
|
|
786
967
|
```ruby
|
787
968
|
result = Result.new(id: '123', creation_date: '2012-03-30 17:23:28')
|
788
|
-
result.id.class # => Fixnum
|
969
|
+
result.id.class # => Integer (Fixnum if you are using Ruby 2.3 or lower)
|
789
970
|
result.created_at.class # => Time
|
790
971
|
```
|
791
972
|
|
@@ -852,6 +1033,6 @@ See [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
852
1033
|
|
853
1034
|
## Copyright
|
854
1035
|
|
855
|
-
Copyright (c) 2009-2014 Intridea, Inc. (http://intridea.com/) and [contributors](https://github.com/
|
1036
|
+
Copyright (c) 2009-2014 Intridea, Inc. (http://intridea.com/) and [contributors](https://github.com/hashie/hashie/graphs/contributors).
|
856
1037
|
|
857
1038
|
MIT License. See [LICENSE](LICENSE) for details.
|
data/Rakefile
CHANGED
@@ -24,9 +24,9 @@ task :integration_specs do
|
|
24
24
|
run_all_integration_specs(handler: handler, logger: ->(msg) { puts msg })
|
25
25
|
|
26
26
|
if status_codes.any?
|
27
|
-
|
27
|
+
warn "#{status_codes.size} integration test(s) failed"
|
28
28
|
exit status_codes.last
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
task default: [
|
32
|
+
task default: %i[rubocop spec integration_specs]
|
data/UPGRADING.md
CHANGED
@@ -1,6 +1,84 @@
|
|
1
1
|
Upgrading Hashie
|
2
2
|
================
|
3
3
|
|
4
|
+
### Upgrading to 4.0.0
|
5
|
+
|
6
|
+
#### Non-destructive Hash methods called on Mash
|
7
|
+
|
8
|
+
The following non-destructive Hash methods called on Mash will now return an instance of the class it was called on.
|
9
|
+
|
10
|
+
| method | ruby |
|
11
|
+
| ----------------- | ---- |
|
12
|
+
| #compact | |
|
13
|
+
| #invert | |
|
14
|
+
| #reject | |
|
15
|
+
| #select | |
|
16
|
+
| #slice | 2.5 |
|
17
|
+
| #transform_keys | 2.5 |
|
18
|
+
| #transform_values | 2.4 |
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class Parents < Hashie::Mash; end
|
22
|
+
|
23
|
+
parents = Parents.new(father: 'Dad', mother: 'Mom')
|
24
|
+
cool_parents = parents.transform_values { |v| v + v[-1] + 'io'}
|
25
|
+
|
26
|
+
p cool_parents
|
27
|
+
|
28
|
+
# before:
|
29
|
+
{"father"=>"Daddio", "mother"=>"Mommio"}
|
30
|
+
=> {"father"=>"Daddio", "mother"=>"Mommio"}
|
31
|
+
|
32
|
+
# after:
|
33
|
+
#<Parents father="Daddio" mother="Mommio">
|
34
|
+
=> {"father"=>"Dad", "mother"=>"Mom"}
|
35
|
+
```
|
36
|
+
|
37
|
+
This may make places where you had to re-make the Mash redundant, and may cause unintended side effects if your application was expecting a plain old ruby Hash.
|
38
|
+
|
39
|
+
#### Ruby 2.6: Mash#merge and Mash#merge!
|
40
|
+
|
41
|
+
In Ruby > 2.6.0, Hashie now supports passing multiple hash and Mash objects to Mash#merge and Mash#merge!.
|
42
|
+
|
43
|
+
#### Hashie::Mash::CannotDisableMashWarnings error class is removed
|
44
|
+
|
45
|
+
There shouldn't really be a case that anyone was relying on catching this specific error, but if so, they should change it to rescue Hashie::Extensions::KeyConflictWarning::CannotDisableMashWarnings
|
46
|
+
|
47
|
+
### Upgrading to 3.7.0
|
48
|
+
|
49
|
+
#### Mash#load takes options
|
50
|
+
|
51
|
+
The `Hashie::Mash#load` method now accepts options, changing the interface of `Parser#initialize`. If you have a custom parser, you must update its `initialize` method.
|
52
|
+
|
53
|
+
For example, `Hashie::Extensions::Parsers::YamlErbParser` now accepts `permitted_classes`, `permitted_symbols` and `aliases` options.
|
54
|
+
|
55
|
+
Before:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Hashie::Extensions::Parsers::YamlErbParser
|
59
|
+
def initialize(file_path)
|
60
|
+
@file_path = file_path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
After:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class Hashie::Extensions::Parsers::YamlErbParser
|
69
|
+
def initialize(file_path, options = {})
|
70
|
+
@file_path = file_path
|
71
|
+
@options = options
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
Options can now be passed into `Mash#load`.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Mash.load(filename, permitted_classes: [])
|
80
|
+
```
|
81
|
+
|
4
82
|
### Upgrading to 3.5.2
|
5
83
|
|
6
84
|
#### Disable logging in Mash subclasses
|
@@ -65,7 +143,7 @@ h.abb? # => false
|
|
65
143
|
|
66
144
|
#### Possible coercion changes
|
67
145
|
|
68
|
-
The improvements made to coercions in version 3.2.1 [issue #200](https://github.com/
|
146
|
+
The improvements made to coercions in version 3.2.1 [issue #200](https://github.com/hashie/hashie/pull/200) do not break the documented API, but are significant enough that changes may effect undocumented side-effects. Applications that depended on those side-effects will need to be updated.
|
69
147
|
|
70
148
|
**Change**: Type coercion no longer creates new objects if the input matches the target type. Previously coerced properties always resulted in the creation of a new object, even when it wasn't necessary. This had the effect of a `dup` or `clone` on coerced properties but not uncoerced ones.
|
71
149
|
|
@@ -81,7 +159,7 @@ Applications that were attempting to rescuing the internal errors should be upda
|
|
81
159
|
|
82
160
|
#### Compatibility with Rails 4 Strong Parameters
|
83
161
|
|
84
|
-
Version 2.1 introduced support to prevent default Rails 4 mass-assignment protection behavior. This was [issue #89](https://github.com/
|
162
|
+
Version 2.1 introduced support to prevent default Rails 4 mass-assignment protection behavior. This was [issue #89](https://github.com/hashie/hashie/issues/89), resolved in [#104](https://github.com/hashie/hashie/pull/104). In version 2.2 this behavior has been removed in [#147](https://github.com/hashie/hashie/pull/147) in favor of a mixin and finally extracted into a separate gem in Hashie 3.0.
|
85
163
|
|
86
164
|
To enable 2.1 compatible behavior with Rails 4, use the [hashie_rails](http://rubygems.org/gems/hashie_rails) gem.
|
87
165
|
|
@@ -89,7 +167,7 @@ To enable 2.1 compatible behavior with Rails 4, use the [hashie_rails](http://ru
|
|
89
167
|
gem 'hashie_rails'
|
90
168
|
```
|
91
169
|
|
92
|
-
See [#154](https://github.com/
|
170
|
+
See [#154](https://github.com/hashie/hashie/pull/154) and [Mash and Rails 4 Strong Parameters](README.md#mash-and-rails-4-strong-parameters) for more details.
|
93
171
|
|
94
172
|
#### Key Conversions in Hashie::Dash and Hashie::Trash
|
95
173
|
|
@@ -117,7 +195,7 @@ p.inspect # => { 'name' => 'dB.' }
|
|
117
195
|
p.to_hash # => { 'name' => 'dB.' }
|
118
196
|
```
|
119
197
|
|
120
|
-
It was not possible to achieve the behavior of preserving keys, as described in [issue #151](https://github.com/
|
198
|
+
It was not possible to achieve the behavior of preserving keys, as described in [issue #151](https://github.com/hashie/hashie/issues/151).
|
121
199
|
|
122
200
|
Version 2.2 does not perform this conversion by default.
|
123
201
|
|
@@ -164,6 +242,4 @@ instance.to_hash # => { :first => 'First', "last" => 'Last' }
|
|
164
242
|
|
165
243
|
The behavior with `symbolize_keys` and `stringify_keys` is unchanged.
|
166
244
|
|
167
|
-
See [#152](https://github.com/
|
168
|
-
|
169
|
-
|
245
|
+
See [#152](https://github.com/hashie/hashie/pull/152) for more information.
|