hashie 3.5.7 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +240 -164
  3. data/CONTRIBUTING.md +13 -6
  4. data/README.md +210 -29
  5. data/Rakefile +2 -2
  6. data/UPGRADING.md +83 -7
  7. data/hashie.gemspec +13 -7
  8. data/lib/hashie.rb +21 -19
  9. data/lib/hashie/clash.rb +12 -1
  10. data/lib/hashie/dash.rb +42 -21
  11. data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
  12. data/lib/hashie/extensions/coercion.rb +26 -19
  13. data/lib/hashie/extensions/dash/indifferent_access.rb +20 -1
  14. data/lib/hashie/extensions/dash/property_translation.rb +54 -28
  15. data/lib/hashie/extensions/deep_fetch.rb +5 -3
  16. data/lib/hashie/extensions/deep_find.rb +14 -5
  17. data/lib/hashie/extensions/deep_locate.rb +22 -8
  18. data/lib/hashie/extensions/deep_merge.rb +26 -10
  19. data/lib/hashie/extensions/indifferent_access.rb +8 -8
  20. data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
  21. data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
  22. data/lib/hashie/extensions/mash/keep_original_keys.rb +4 -5
  23. data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
  24. data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
  25. data/lib/hashie/extensions/mash/symbolize_keys.rb +1 -1
  26. data/lib/hashie/extensions/method_access.rb +47 -14
  27. data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +28 -4
  28. data/lib/hashie/extensions/ruby_version_check.rb +5 -1
  29. data/lib/hashie/extensions/strict_key_access.rb +16 -13
  30. data/lib/hashie/extensions/stringify_keys.rb +1 -1
  31. data/lib/hashie/extensions/symbolize_keys.rb +1 -1
  32. data/lib/hashie/hash.rb +18 -11
  33. data/lib/hashie/mash.rb +131 -70
  34. data/lib/hashie/railtie.rb +7 -0
  35. data/lib/hashie/rash.rb +6 -6
  36. data/lib/hashie/utils.rb +28 -0
  37. data/lib/hashie/version.rb +1 -1
  38. metadata +19 -128
  39. data/spec/hashie/array_spec.rb +0 -29
  40. data/spec/hashie/clash_spec.rb +0 -70
  41. data/spec/hashie/dash_spec.rb +0 -573
  42. data/spec/hashie/extensions/autoload_spec.rb +0 -24
  43. data/spec/hashie/extensions/coercion_spec.rb +0 -631
  44. data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
  45. data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
  46. data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
  47. data/spec/hashie/extensions/deep_find_spec.rb +0 -138
  48. data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
  49. data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
  50. data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
  51. data/spec/hashie/extensions/indifferent_access_spec.rb +0 -282
  52. data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
  53. data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
  54. data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
  55. data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
  56. data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
  57. data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
  58. data/spec/hashie/extensions/method_access_spec.rb +0 -188
  59. data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
  60. data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
  61. data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
  62. data/spec/hashie/hash_spec.rb +0 -84
  63. data/spec/hashie/mash_spec.rb +0 -763
  64. data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
  65. data/spec/hashie/rash_spec.rb +0 -83
  66. data/spec/hashie/trash_spec.rb +0 -268
  67. data/spec/hashie/utils_spec.rb +0 -25
  68. data/spec/hashie/version_spec.rb +0 -7
  69. data/spec/hashie_spec.rb +0 -13
  70. data/spec/integration/omniauth-oauth2/app.rb +0 -53
  71. data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
  72. data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
  73. data/spec/integration/omniauth/app.rb +0 -11
  74. data/spec/integration/omniauth/integration_spec.rb +0 -38
  75. data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
  76. data/spec/integration/rails/app.rb +0 -48
  77. data/spec/integration/rails/integration_spec.rb +0 -26
  78. data/spec/spec_helper.rb +0 -23
  79. data/spec/support/integration_specs.rb +0 -36
  80. data/spec/support/logger.rb +0 -24
  81. data/spec/support/module_context.rb +0 -11
  82. 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/intridea/hashie/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/intridea/hashie/pulls), [propose features and discuss issues](https://github.com/intridea/hashie/issues).
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/intridea/hashie) and check out your copy.
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/intridea/hashie.git
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
- #### Bundle Install and Test
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/intridea/hashie/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
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/intridea/hashie](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/intridea/hashie?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
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/intridea/hashie.svg)](https://travis-ci.org/intridea/hashie)
7
- [![Dependency Status](https://gemnasium.com/intridea/hashie.svg)](https://gemnasium.com/intridea/hashie)
8
- [![Code Climate](https://codeclimate.com/github/intridea/hashie.svg)](https://codeclimate.com/github/intridea/hashie)
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
- ## Upgrading
19
+ ## Stable Release
22
20
 
23
- You're reading the documentation for the stable release of Hashie, 3.5.7. Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
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 coercion boolean values, since Ruby does not have a built-in boolean type or standard method for to a boolean. You can coerce to booleans using a custom proc.
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 allow you to easily include a recursive merging
302
- system to any Hash descendant:
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
- ### Example:
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
- ### Example:
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
- 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:
634
+ The `Mash#load` method calls `YAML.safe_load(path, [], [], true)`.
535
635
 
536
- ```ruby
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
- class Response < Hashie::Mash
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:: SymbolizeKeys
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/intridea/hashie/graphs/contributors).
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
- $stderr.puts "#{status_codes.size} integration test(s) failed"
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: [:rubocop, :spec, :integration_specs]
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/intridea/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.
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/intridea/hashie/issues/89), resolved in [#104](https://github.com/intridea/hashie/pull/104). In version 2.2 this behavior has been removed in [#147](https://github.com/intridea/hashie/pull/147) in favor of a mixin and finally extracted into a separate gem in Hashie 3.0.
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/intridea/hashie/pull/154) and [Mash and Rails 4 Strong Parameters](README.md#mash-and-rails-4-strong-parameters) for more details.
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/intridea/hashie/issues/151).
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/intridea/hashie/pull/152) for more information.
168
-
169
-
245
+ See [#152](https://github.com/hashie/hashie/pull/152) for more information.