hashie 3.6.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +271 -207
- data/CONTRIBUTING.md +13 -6
- data/LICENSE +1 -1
- data/README.md +245 -54
- data/UPGRADING.md +121 -7
- data/hashie.gemspec +13 -7
- data/lib/hashie/dash.rb +18 -17
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/coercion.rb +23 -16
- data/lib/hashie/extensions/dash/indifferent_access.rb +29 -1
- data/lib/hashie/extensions/dash/predefined_values.rb +88 -0
- data/lib/hashie/extensions/dash/property_translation.rb +12 -4
- data/lib/hashie/extensions/deep_fetch.rb +4 -2
- data/lib/hashie/extensions/deep_find.rb +12 -3
- data/lib/hashie/extensions/deep_locate.rb +22 -7
- data/lib/hashie/extensions/deep_merge.rb +18 -1
- data/lib/hashie/extensions/ignore_undeclared.rb +4 -5
- data/lib/hashie/extensions/indifferent_access.rb +37 -6
- 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 +2 -1
- 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 +5 -5
- data/lib/hashie/extensions/method_access.rb +5 -2
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +26 -4
- data/lib/hashie/extensions/ruby_version_check.rb +5 -1
- data/lib/hashie/extensions/strict_key_access.rb +8 -4
- data/lib/hashie/extensions/symbolize_keys.rb +12 -1
- data/lib/hashie/hash.rb +16 -9
- data/lib/hashie/mash.rb +130 -64
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/utils.rb +28 -0
- data/lib/hashie/version.rb +1 -1
- data/lib/hashie.rb +22 -19
- metadata +23 -133
- data/spec/hashie/array_spec.rb +0 -29
- data/spec/hashie/clash_spec.rb +0 -70
- data/spec/hashie/dash_spec.rb +0 -598
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -639
- 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 -295
- 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 -226
- 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 -771
- 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 -328
- 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/elasticsearch/integration_spec.rb +0 -40
- data/spec/integration/omniauth/app.rb +0 -11
- data/spec/integration/omniauth/integration_spec.rb +0 -38
- data/spec/integration/omniauth-oauth2/app.rb +0 -52
- data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
- data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
- data/spec/integration/rails/app.rb +0 -47
- data/spec/integration/rails/integration_spec.rb +0 -26
- data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
- 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/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,56 @@
|
|
1
1
|
# Hashie
|
2
2
|
|
3
|
-
[](https://gitter.im/hashie/hashie?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
4
|
[](http://badge.fury.io/rb/hashie)
|
5
|
-
[](https://github.com/hashie/hashie/actions/workflows/main.yml)
|
6
|
+
|
7
|
+
[](#mascot) Hashie is a growing collection of tools that extend Hashes and make them more useful.
|
8
|
+
|
9
|
+
# Table of Contents
|
10
|
+
|
11
|
+
- [Hashie](#hashie)
|
12
|
+
- [Table of Contents](#table-of-contents)
|
13
|
+
- [Installation](#installation)
|
14
|
+
- [Stable Release](#stable-release)
|
15
|
+
- [Hash Extensions](#hash-extensions)
|
16
|
+
- [Logging](#logging)
|
17
|
+
- [Coercion](#coercion)
|
18
|
+
- [Coercing Collections](#coercing-collections)
|
19
|
+
- [Coercing Hashes](#coercing-hashes)
|
20
|
+
- [Coercing Core Types](#coercing-core-types)
|
21
|
+
- [Coercion Proc](#coercion-proc)
|
22
|
+
- [A note on circular coercion](#a-note-on-circular-coercion)
|
23
|
+
- [KeyConversion](#keyconversion)
|
24
|
+
- [MergeInitializer](#mergeinitializer)
|
25
|
+
- [MethodAccess](#methodaccess)
|
26
|
+
- [MethodAccessWithOverride](#methodaccesswithoverride)
|
27
|
+
- [MethodOverridingInitializer](#methodoverridinginitializer)
|
28
|
+
- [IndifferentAccess](#indifferentaccess)
|
29
|
+
- [IgnoreUndeclared](#ignoreundeclared)
|
30
|
+
- [DeepMerge](#deepmerge)
|
31
|
+
- [DeepFetch](#deepfetch)
|
32
|
+
- [DeepFind](#deepfind)
|
33
|
+
- [DeepLocate](#deeplocate)
|
34
|
+
- [StrictKeyAccess](#strictkeyaccess)
|
35
|
+
- [Mash](#mash)
|
36
|
+
- [KeepOriginalKeys](#keeporiginalkeys)
|
37
|
+
- [PermissiveRespondTo](#permissiverespondto)
|
38
|
+
- [SafeAssignment](#safeassignment)
|
39
|
+
- [SymbolizeKeys](#symbolizekeys)
|
40
|
+
- [DefineAccessors](#defineaccessors)
|
41
|
+
- [Dash](#dash)
|
42
|
+
- [Potential Gotchas](#potential-gotchas)
|
43
|
+
- [PropertyTranslation](#propertytranslation)
|
44
|
+
- [Mash and Rails 4 Strong Parameters](#mash-and-rails-4-strong-parameters)
|
45
|
+
- [Coercion](#coercion-1)
|
46
|
+
- [PredefinedValues](#predefinedvalues)
|
47
|
+
- [Trash](#trash)
|
48
|
+
- [Clash](#clash)
|
49
|
+
- [Rash](#rash)
|
50
|
+
- [Auto-Optimized](#auto-optimized)
|
51
|
+
- [Mascot](#mascot)
|
52
|
+
- [Contributing](#contributing)
|
53
|
+
- [Copyright](#copyright)
|
10
54
|
|
11
55
|
## Installation
|
12
56
|
|
@@ -16,9 +60,9 @@ Hashie is available as a RubyGem:
|
|
16
60
|
$ gem install hashie
|
17
61
|
```
|
18
62
|
|
19
|
-
##
|
63
|
+
## Stable Release
|
20
64
|
|
21
|
-
You're reading the documentation for the stable release of Hashie,
|
65
|
+
You're reading the documentation for the stable release of Hashie, v5.0.0.
|
22
66
|
|
23
67
|
## Hash Extensions
|
24
68
|
|
@@ -195,8 +239,8 @@ The KeyConversion extension gives you the convenience methods of `symbolize_keys
|
|
195
239
|
Hashie also has a utility method for converting keys on a Hash without a mixin:
|
196
240
|
|
197
241
|
```ruby
|
198
|
-
Hashie.symbolize_keys! hash # => Symbolizes keys of hash.
|
199
|
-
Hashie.symbolize_keys hash # => Returns a copy of hash with keys symbolized.
|
242
|
+
Hashie.symbolize_keys! hash # => Symbolizes all string keys of hash.
|
243
|
+
Hashie.symbolize_keys hash # => Returns a copy of hash with string keys symbolized.
|
200
244
|
Hashie.stringify_keys! hash # => Stringifies keys of hash.
|
201
245
|
Hashie.stringify_keys hash # => Returns a copy of hash with keys stringified.
|
202
246
|
```
|
@@ -269,8 +313,6 @@ This extension can be mixed in to your Hash subclass to allow you to use Strings
|
|
269
313
|
|
270
314
|
In addition, IndifferentAccess will also inject itself into sub-hashes so they behave the same.
|
271
315
|
|
272
|
-
Example:
|
273
|
-
|
274
316
|
```ruby
|
275
317
|
class MyHash < Hash
|
276
318
|
include Hashie::Extensions::MergeInitializer
|
@@ -290,6 +332,18 @@ myhash['fishes'][:food] = 'flakes'
|
|
290
332
|
myhash['fishes']['food'] # => "flakes"
|
291
333
|
```
|
292
334
|
|
335
|
+
To get back a normal, not-indifferent Hash, you can use `#to_hash` on the indifferent hash. It exports the keys as strings, not symbols:
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
myhash = MyHash.new
|
339
|
+
myhash["foo"] = "bar"
|
340
|
+
myhash[:foo] #=> "bar"
|
341
|
+
|
342
|
+
normal_hash = myhash.to_hash
|
343
|
+
myhash["foo"] #=> "bar"
|
344
|
+
myhash[:foo] #=> nil
|
345
|
+
```
|
346
|
+
|
293
347
|
### IgnoreUndeclared
|
294
348
|
|
295
349
|
This extension can be mixed in to silently ignore undeclared properties on initialization instead of raising an error. This is useful when using a Trash to capture a subset of a larger hash.
|
@@ -316,8 +370,8 @@ p.email # => NoMethodError
|
|
316
370
|
|
317
371
|
### DeepMerge
|
318
372
|
|
319
|
-
This extension
|
320
|
-
system
|
373
|
+
This extension allows you to easily include a recursive merging
|
374
|
+
system into any Hash descendant:
|
321
375
|
|
322
376
|
```ruby
|
323
377
|
class MyHash < Hash
|
@@ -445,8 +499,6 @@ books.deep_locate -> (key, value, object) { key == :pages && value <= 120 }
|
|
445
499
|
|
446
500
|
This extension can be mixed in to allow a Hash to raise an error when attempting to extract a value using a non-existent key.
|
447
501
|
|
448
|
-
### Example:
|
449
|
-
|
450
502
|
```ruby
|
451
503
|
class StrictKeyAccessHash < Hash
|
452
504
|
include Hashie::Extensions::StrictKeyAccess
|
@@ -464,8 +516,6 @@ end
|
|
464
516
|
|
465
517
|
Mash is an extended Hash that gives simple pseudo-object functionality that can be built from hashes and easily extended. It is intended to give the user easier access to the objects within the Mash through a property-like syntax, while still retaining all Hash functionality.
|
466
518
|
|
467
|
-
### Example:
|
468
|
-
|
469
519
|
```ruby
|
470
520
|
mash = Hashie::Mash.new
|
471
521
|
mash.name? # => false
|
@@ -488,12 +538,10 @@ mash.inspect # => <Hashie::Mash>
|
|
488
538
|
|
489
539
|
**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.
|
490
540
|
|
491
|
-
|
541
|
+
_How does Mash handle conflicts with pre-existing methods?_
|
492
542
|
|
493
543
|
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.
|
494
544
|
|
495
|
-
#### Example:
|
496
|
-
|
497
545
|
```ruby
|
498
546
|
mash = Hashie::Mash.new
|
499
547
|
mash.name = "My Mash"
|
@@ -515,11 +563,58 @@ class Response < Hashie::Mash
|
|
515
563
|
end
|
516
564
|
```
|
517
565
|
|
518
|
-
|
566
|
+
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
567
|
|
520
|
-
|
568
|
+
```ruby
|
569
|
+
class Response < Hashie::Mash
|
570
|
+
disable_warnings :zip, :zap
|
571
|
+
end
|
572
|
+
```
|
573
|
+
|
574
|
+
This behavior is cumulative. The examples above and below behave identically.
|
575
|
+
|
576
|
+
```ruby
|
577
|
+
class Response < Hashie::Mash
|
578
|
+
disable_warnings :zip
|
579
|
+
disable_warnings :zap
|
580
|
+
end
|
581
|
+
```
|
582
|
+
|
583
|
+
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.
|
584
|
+
|
585
|
+
```ruby
|
586
|
+
class Message < Hashie::Mash
|
587
|
+
disable_warnings :zip, :zap
|
588
|
+
disable_warnings
|
589
|
+
end
|
590
|
+
|
591
|
+
# No errors will be logged
|
592
|
+
Message.new(merge: 'true', compact: true)
|
593
|
+
```
|
594
|
+
|
595
|
+
```ruby
|
596
|
+
class Message < Hashie::Mash
|
597
|
+
disable_warnings
|
598
|
+
end
|
599
|
+
|
600
|
+
class Response < Message
|
601
|
+
disable_warnings :zip, :zap
|
602
|
+
end
|
521
603
|
|
522
|
-
|
604
|
+
# 2 errors will be logged
|
605
|
+
Response.new(merge: 'true', compact: true, zip: '90210', zap: 'electric')
|
606
|
+
```
|
607
|
+
|
608
|
+
If you would like to create an anonymous subclass of a Hashie::Mash with key conflict warnings disabled:
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
Hashie::Mash.quiet.new(zip: '90210', compact: true) # no errors logged
|
612
|
+
Hashie::Mash.quiet(:zip).new(zip: '90210', compact: true) # error logged for compact
|
613
|
+
```
|
614
|
+
|
615
|
+
_How does the wrapping of Mash sub-Hashes work?_
|
616
|
+
|
617
|
+
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.
|
523
618
|
|
524
619
|
```ruby
|
525
620
|
mash = Hashie::Mash.new(name: "Hashie", dependencies: { rake: "< 11", rspec: "~> 3.0" })
|
@@ -530,11 +625,20 @@ my_gem = MyGem.new(name: "Hashie", dependencies: { rake: "< 11", rspec: "~> 3.0"
|
|
530
625
|
my_gem.dependencies.class #=> MyGem
|
531
626
|
```
|
532
627
|
|
533
|
-
|
628
|
+
_How does Mash handle key types which cannot be symbolized?_
|
534
629
|
|
535
|
-
Mash
|
630
|
+
Mash preserves keys which cannot be converted *directly* to both a string and a symbol, such as numeric keys. Since Mash is conceived to provide psuedo-object functionality, handling keys which cannot represent a method call falls outside its scope of value.
|
536
631
|
|
537
|
-
|
632
|
+
```ruby
|
633
|
+
Hashie::Mash.new('1' => 'one string', :'1' => 'one sym', 1 => 'one num')
|
634
|
+
# => {"1"=>"one sym", 1=>"one num"}
|
635
|
+
```
|
636
|
+
|
637
|
+
The symbol key `:'1'` is converted the string `'1'` to support indifferent access and consequently its value `'one sym'` will override the previously set `'one string'`. However, the subsequent key of `1` cannot directly convert to a symbol and therefore **not** converted to the string `'1'` that would otherwise override the previously set value of `'one sym'`.
|
638
|
+
|
639
|
+
_What else can Mash do?_
|
640
|
+
|
641
|
+
Mash allows you also to transform any files into a Mash objects.
|
538
642
|
|
539
643
|
```yml
|
540
644
|
#/etc/config/settings/twitter.yml
|
@@ -566,7 +670,7 @@ Twitter.extend mash.to_module # NOTE: if you want another name than settings, ca
|
|
566
670
|
Twitter.settings.api_key # => 'abcd'
|
567
671
|
```
|
568
672
|
|
569
|
-
You can use another parser (by default: YamlErbParser):
|
673
|
+
You can use another parser (by default: [YamlErbParser](lib/hashie/extensions/parsers/yaml_erb_parser.rb)):
|
570
674
|
|
571
675
|
```
|
572
676
|
#/etc/data/user.csv
|
@@ -582,9 +686,17 @@ mash = Mash.load('data/user.csv', parser: MyCustomCsvParser)
|
|
582
686
|
mash[1] #=> { name: 'John', lastname: 'Doe' }
|
583
687
|
```
|
584
688
|
|
585
|
-
|
689
|
+
The `Mash#load` method calls `YAML.safe_load(path, [], [], true)`.
|
690
|
+
|
691
|
+
Specify `permitted_symbols`, `permitted_classes` and `aliases` options as needed.
|
692
|
+
|
693
|
+
```ruby
|
694
|
+
Mash.load('data/user.csv', permitted_classes: [Symbol], permitted_symbols: [], aliases: false)
|
695
|
+
```
|
696
|
+
|
697
|
+
### KeepOriginalKeys
|
586
698
|
|
587
|
-
This extension can be mixed into a Mash to keep the form of any keys passed directly into the Mash. By default, Mash converts keys to strings to give indifferent access. This extension still allows indifferent access, but keeps the form of the keys to eliminate confusion when you're not expecting the keys to change.
|
699
|
+
This extension can be mixed into a Mash to keep the form of any keys passed directly into the Mash. By default, Mash converts symbol keys to strings to give indifferent access. This extension still allows indifferent access, but keeps the form of the keys to eliminate confusion when you're not expecting the keys to change.
|
588
700
|
|
589
701
|
```ruby
|
590
702
|
class KeepingMash < ::Hashie::Mash
|
@@ -601,11 +713,33 @@ mash['string_key'] #=> 'string'
|
|
601
713
|
mash[:string_key] #=> 'string'
|
602
714
|
```
|
603
715
|
|
604
|
-
###
|
716
|
+
### PermissiveRespondTo
|
605
717
|
|
606
|
-
|
718
|
+
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:
|
719
|
+
|
720
|
+
```ruby
|
721
|
+
mash = Hashie::Mash.new(a: 1)
|
722
|
+
mash.respond_to? :b #=> false
|
723
|
+
```
|
724
|
+
|
725
|
+
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.
|
726
|
+
|
727
|
+
In order to have a SimpleDelegator-compatible Mash, you can use the `PermissiveRespondTo` extension to make Mash respond to anything.
|
728
|
+
|
729
|
+
```ruby
|
730
|
+
class PermissiveMash < Hashie::Mash
|
731
|
+
include Hashie::Extensions::Mash::PermissiveRespondTo
|
732
|
+
end
|
733
|
+
|
734
|
+
mash = PermissiveMash.new(a: 1)
|
735
|
+
mash.respond_to? :b #=> true
|
736
|
+
```
|
607
737
|
|
608
|
-
|
738
|
+
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.
|
739
|
+
|
740
|
+
### SafeAssignment
|
741
|
+
|
742
|
+
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.
|
609
743
|
|
610
744
|
```ruby
|
611
745
|
class SafeMash < ::Hashie::Mash
|
@@ -617,9 +751,9 @@ safe_mash.zip = 'Test' # => ArgumentError
|
|
617
751
|
safe_mash[:zip] = 'test' # => still ArgumentError
|
618
752
|
```
|
619
753
|
|
620
|
-
###
|
754
|
+
### SymbolizeKeys
|
621
755
|
|
622
|
-
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.
|
756
|
+
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 string keys to symbols. It can be useful to use with keywords argument, which required symbol keys.
|
623
757
|
|
624
758
|
```ruby
|
625
759
|
class SymbolizedMash < ::Hashie::Mash
|
@@ -630,6 +764,12 @@ symbol_mash = SymbolizedMash.new
|
|
630
764
|
symbol_mash['test'] = 'value'
|
631
765
|
symbol_mash.test #=> 'value'
|
632
766
|
symbol_mash.to_h #=> {test: 'value'}
|
767
|
+
|
768
|
+
def example(test:)
|
769
|
+
puts test
|
770
|
+
end
|
771
|
+
|
772
|
+
example(symbol_mash) #=> value
|
633
773
|
```
|
634
774
|
|
635
775
|
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:
|
@@ -644,14 +784,37 @@ end
|
|
644
784
|
|
645
785
|
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.
|
646
786
|
|
787
|
+
### DefineAccessors
|
788
|
+
|
789
|
+
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.
|
790
|
+
|
791
|
+
```ruby
|
792
|
+
class MyHash < ::Hashie::Mash
|
793
|
+
include Hashie::Extensions::Mash::DefineAccessors
|
794
|
+
end
|
795
|
+
|
796
|
+
mash = MyHash.new
|
797
|
+
MyHash.method_defined?(:foo=) #=> false
|
798
|
+
mash.foo = 123
|
799
|
+
MyHash.method_defined?(:foo=) #=> true
|
800
|
+
|
801
|
+
MyHash.method_defined?(:foo) #=> false
|
802
|
+
mash.foo #=> 123
|
803
|
+
MyHash.method_defined?(:foo) #=> true
|
804
|
+
```
|
805
|
+
|
806
|
+
You can also extend the existing mash without defining a class:
|
807
|
+
|
808
|
+
```ruby
|
809
|
+
mash = ::Hashie::Mash.new.with_accessors!
|
810
|
+
```
|
811
|
+
|
647
812
|
## Dash
|
648
813
|
|
649
814
|
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.
|
650
815
|
|
651
816
|
You can also conditionally require certain properties by passing a Proc or Symbol. If a Proc is provided, it will be run in the context of the Dash instance. If a Symbol is provided, the value returned for the property or method of the same name will be evaluated. The property will be required if the result of the conditional is truthy.
|
652
817
|
|
653
|
-
### Example:
|
654
|
-
|
655
818
|
```ruby
|
656
819
|
class Person < Hashie::Dash
|
657
820
|
property :name, required: true
|
@@ -688,8 +851,6 @@ p.occupation # => 'Rubyist'
|
|
688
851
|
|
689
852
|
Properties defined as symbols are not the same thing as properties defined as strings.
|
690
853
|
|
691
|
-
### Example:
|
692
|
-
|
693
854
|
```ruby
|
694
855
|
class Tricky < Hashie::Dash
|
695
856
|
property :trick
|
@@ -713,7 +874,28 @@ p = Tricky.new('trick' => 'two')
|
|
713
874
|
p.trick # => NoMethodError
|
714
875
|
```
|
715
876
|
|
716
|
-
|
877
|
+
If you would like to update a Dash and use any default values set in the case of a `nil` value, use `#update_attributes!`.
|
878
|
+
|
879
|
+
```ruby
|
880
|
+
class WithDefaults < Hashie::Dash
|
881
|
+
property :description, default: 'none'
|
882
|
+
end
|
883
|
+
|
884
|
+
dash = WithDefaults.new
|
885
|
+
dash.description #=> 'none'
|
886
|
+
|
887
|
+
dash.description = 'You committed one of the classic blunders!'
|
888
|
+
dash.description #=> 'You committed one of the classic blunders!'
|
889
|
+
|
890
|
+
dash.description = nil
|
891
|
+
dash.description #=> nil
|
892
|
+
|
893
|
+
dash.description = 'Only slightly less known is ...'
|
894
|
+
dash.update_attributes!(description: nil)
|
895
|
+
dash.description #=> 'none'
|
896
|
+
```
|
897
|
+
|
898
|
+
### Potential Gotchas
|
717
899
|
|
718
900
|
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:
|
719
901
|
|
@@ -745,13 +927,11 @@ qux.is_a?(Hash) #=> true
|
|
745
927
|
qux[:quux] #=> "corge"
|
746
928
|
```
|
747
929
|
|
748
|
-
###
|
930
|
+
### PropertyTranslation
|
749
931
|
|
750
932
|
The `Hashie::Extensions::Dash::PropertyTranslation` mixin extends a Dash with
|
751
933
|
the ability to remap keys from a source hash.
|
752
934
|
|
753
|
-
### Example from inconsistent APIs
|
754
|
-
|
755
935
|
Property translation is useful when you need to read data from another
|
756
936
|
application -- such as a Java API -- where the keys are named differently from
|
757
937
|
Ruby conventions.
|
@@ -771,8 +951,6 @@ person[:first_name] #=> 'Michael'
|
|
771
951
|
person[:last_name] #=> 'Bleigh
|
772
952
|
```
|
773
953
|
|
774
|
-
### Example using translation lambdas
|
775
|
-
|
776
954
|
You can also use a lambda to translate the value. This is particularly useful
|
777
955
|
when you want to ensure the type of data you're wrapping.
|
778
956
|
|
@@ -785,7 +963,7 @@ class DataModelHash < Hashie::Dash
|
|
785
963
|
end
|
786
964
|
|
787
965
|
model = DataModelHash.new(id: '123', created: '2014-04-25 22:35:28')
|
788
|
-
model.id.class #=> Fixnum
|
966
|
+
model.id.class #=> Integer (Fixnum if you are using Ruby 2.3 or lower)
|
789
967
|
model.created_at.class #=> Time
|
790
968
|
```
|
791
969
|
|
@@ -793,7 +971,7 @@ model.created_at.class #=> Time
|
|
793
971
|
|
794
972
|
To enable compatibility with Rails 4 use the [hashie-forbidden_attributes](https://github.com/Maxim-Filimonov/hashie-forbidden_attributes) gem.
|
795
973
|
|
796
|
-
###
|
974
|
+
### Coercion
|
797
975
|
|
798
976
|
If you want to use `Hashie::Extensions::Coercion` together with `Dash` then
|
799
977
|
you may probably want to use `Hashie::Extensions::Dash::Coercion` instead.
|
@@ -823,6 +1001,20 @@ class UserHash < Hashie::Dash
|
|
823
1001
|
end
|
824
1002
|
```
|
825
1003
|
|
1004
|
+
### PredefinedValues
|
1005
|
+
|
1006
|
+
The `Hashie::Extensions::Dash::PredefinedValues` mixin extends a Dash with
|
1007
|
+
the ability to accept predefined values on a property.
|
1008
|
+
|
1009
|
+
```ruby
|
1010
|
+
class UserHash < Hashie::Dash
|
1011
|
+
include Hashie::Extensions::Dash::PredefinedValues
|
1012
|
+
|
1013
|
+
property :gender, values: %i[male female prefer_not_to_say]
|
1014
|
+
property :age, values: (0..150)
|
1015
|
+
end
|
1016
|
+
```
|
1017
|
+
|
826
1018
|
## Trash
|
827
1019
|
|
828
1020
|
A Trash is a Dash that allows you to translate keys on initialization. It mixes
|
@@ -854,7 +1046,7 @@ this will produce the following
|
|
854
1046
|
|
855
1047
|
```ruby
|
856
1048
|
result = Result.new(id: '123', creation_date: '2012-03-30 17:23:28')
|
857
|
-
result.id.class # => Fixnum
|
1049
|
+
result.id.class # => Integer (Fixnum if you are using Ruby 2.3 or lower)
|
858
1050
|
result.created_at.class # => Time
|
859
1051
|
```
|
860
1052
|
|
@@ -864,8 +1056,6 @@ Clash is a Chainable Lazy Hash that allows you to easily construct complex hashe
|
|
864
1056
|
|
865
1057
|
Essentially, a Clash is a generalized way to provide much of the same kind of "chainability" that libraries like Arel or Rails 2.x's named_scopes provide.
|
866
1058
|
|
867
|
-
### Example:
|
868
|
-
|
869
1059
|
```ruby
|
870
1060
|
c = Hashie::Clash.new
|
871
1061
|
c.where(abc: 'def').order(:created_at)
|
@@ -891,8 +1081,6 @@ A good use case for the Rash is an URL router for a web framework, where URLs ne
|
|
891
1081
|
|
892
1082
|
If the Rash's value is a `proc`, the `proc` will be automatically called with the regexp's MatchData (matched groups) as a block argument.
|
893
1083
|
|
894
|
-
### Example:
|
895
|
-
|
896
1084
|
```ruby
|
897
1085
|
|
898
1086
|
# Mapping names to appropriate greetings
|
@@ -909,18 +1097,21 @@ mapper["I like traffic lights"] # => "Who DOESN'T like traffic lights?!"
|
|
909
1097
|
mapper["Get off my lawn!"] # => "Forget your lawn, old man!"
|
910
1098
|
```
|
911
1099
|
|
912
|
-
### Auto-
|
1100
|
+
### Auto-Optimized
|
913
1101
|
|
914
1102
|
**Note:** The Rash is automatically optimized every 500 accesses (which means that it sorts the list of Regexps, putting the most frequently matched ones at the beginning).
|
915
1103
|
|
916
1104
|
If this value is too low or too high for your needs, you can tune it by setting: `rash.optimize_every = n`.
|
917
1105
|
|
1106
|
+
## Mascot
|
1107
|
+
[](https://en.wiktionary.org/wiki/eierlegende_Wollmilchsau) Meet Hashie's "offical" mascot, the [eierlegende Wollmilchsau](https://en.wiktionary.org/wiki/eierlegende_Wollmilchsau)!
|
1108
|
+
|
918
1109
|
## Contributing
|
919
1110
|
|
920
1111
|
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
921
1112
|
|
922
1113
|
## Copyright
|
923
1114
|
|
924
|
-
Copyright (c) 2009-
|
1115
|
+
Copyright (c) 2009-2020 [Intridea, Inc.](http://intridea.com), and [contributors](https://github.com/hashie/hashie/graphs/contributors).
|
925
1116
|
|
926
1117
|
MIT License. See [LICENSE](LICENSE) for details.
|