Hello community, here is the log from the commit of package rubygem-hashie for openSUSE:Factory checked in at 2015-06-12 20:30:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-hashie (Old) and /work/SRC/openSUSE:Factory/.rubygem-hashie.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-hashie" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-hashie/rubygem-hashie.changes 2015-04-10 09:53:57.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-hashie.new/rubygem-hashie.changes 2015-06-12 20:30:46.000000000 +0200 @@ -1,0 +2,6 @@ +Wed Jun 3 04:32:02 UTC 2015 - co...@suse.com + +- updated to version 3.4.2 + see installed CHANGELOG.md + +------------------------------------------------------------------- Old: ---- hashie-3.4.1.gem New: ---- hashie-3.4.2.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-hashie.spec ++++++ --- /var/tmp/diff_new_pack.THHlQF/_old 2015-06-12 20:30:47.000000000 +0200 +++ /var/tmp/diff_new_pack.THHlQF/_new 2015-06-12 20:30:47.000000000 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-hashie -Version: 3.4.1 +Version: 3.4.2 Release: 0 %define mod_name hashie %define mod_full_name %{mod_name}-%{version} ++++++ hashie-3.4.1.gem -> hashie-3.4.2.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md --- old/CHANGELOG.md 2015-03-31 17:04:55.000000000 +0200 +++ new/CHANGELOG.md 2015-06-02 15:48:43.000000000 +0200 @@ -1,11 +1,16 @@ -## 3.4.1 +## 3.4.2 (6/2/2015) + +* [#292](https://github.com/intridea/hashie/pull/292): Removed `Mash#id` and `Mash#type` - [@jrochkind](https://github.com/jrochkind). +* [#297](https://github.com/intridea/hashie/pull/297): Extracted `Trash`'s behavior into a new `Dash::PropertyTranslation` extension - [@michaelherold](https://github.com/michaelherold). + +## 3.4.1 (3/31/2015) * [#269](https://github.com/intridea/hashie/pull/272): Added Hashie::Extensions::DeepLocate - [@msievers](https://github.com/msievers). * [#270](https://github.com/intridea/hashie/pull/277): Fixed ArgumentError raised when using IndifferentAccess and HashWithIndifferentAccess - [@gardenofwine](https://github.com/gardenofwine). * [#281](https://github.com/intridea/hashie/pull/281): Added #reverse_merge to Mash to override ActiveSupport's version - [@mgold](https://github.com/mgold). * [#282](https://github.com/intridea/hashie/pull/282): Fixed coercions in a subclass accumulating in the superclass - [@maxlinc](https://github.com/maxlinc), [@martinstreicher](https://github.com/martinstreicher). -## 3.4.0 (02/02/2015) +## 3.4.0 (2/02/2015) * [#271](https://github.com/intridea/hashie/pull/271): Added ability to define defaults based on current hash - [@gregory](https://github.com/gregory). * [#247](https://github.com/intridea/hashie/pull/247): Fixed #stringify_keys and #symbolize_keys collision with ActiveSupport - [@bartoszkopinski](https://github.com/bartoszkopinski). @@ -72,6 +77,10 @@ * [#148](https://github.com/intridea/hashie/pull/148): Consolidated Hashie::Hash#stringify_keys implementation - [@dblock](https://github.com/dblock). * [#149](https://github.com/intridea/hashie/issues/149): Allow IgnoreUndeclared and DeepMerge to be used with undeclared properties - [@jhaesus](https://github.com/jhaesus). +## 2.1.2 (5/12/2014) + +* [#169](https://github.com/intridea/hashie/pull/169): Hash#to_hash will also convert nested objects that implement `to_hash` - [@gregory](https://github.com/gregory). + ## 2.1.1 (4/12/2014) * [#144](https://github.com/intridea/hashie/issues/144): Fixed regression invoking `to_hash` with no parameters - [@mbleigh](https://github.com/mbleigh). @@ -81,7 +90,7 @@ * [#134](https://github.com/intridea/hashie/pull/134): Add deep_fetch extension for nested access - [@tylerdooling](https://github.com/tylerdooling). * Removed support for Ruby 1.8.7 - [@dblock](https://github.com/dblock). * Ruby style now enforced with Rubocop - [@dblock](https://github.com/dblock). -* [#138](https://github.com/intridea/hashie/pull/138): Added Hashie#Rash, a hash whose keys can be regular expressions or ranges - [@epitron](https://github.com/epitron). +* [#138](https://github.com/intridea/hashie/pull/138): Added Hashie::Rash, a hash whose keys can be regular expressions or ranges - [@epitron](https://github.com/epitron). * [#131](https://github.com/intridea/hashie/pull/131): Added IgnoreUndeclared, an extension to silently ignore undeclared properties at intialization - [@righi](https://github.com/righi). * [#136](https://github.com/intridea/hashie/issues/136): Removed Hashie::Extensions::Structure - [@markiz](https://github.com/markiz). * [#107](https://github.com/intridea/hashie/pull/107): Fixed excessive value conversions, poor performance of deep merge in Hashie::Mash - [@davemitchell](https://github.com/dblock), [@dblock](https://github.com/dblock). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2015-03-31 17:04:55.000000000 +0200 +++ new/README.md 2015-06-02 15:48:43.000000000 +0200 @@ -20,7 +20,7 @@ ## Upgrading -You're reading the documentation for the next release of Hashie, which should be 3.3.2. Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version. The current stable release is [3.3.1](https://github.com/intridea/hashie/blob/v3.3.1/README.md). +You're reading the documentation for the stable release of Hashie, which is 3.4.2. Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version. ## Hash Extensions @@ -145,6 +145,41 @@ end ``` +#### A note on circular coercion + +Since `coerce_key` is a class-level method, you cannot have circular coercion without the use of a proc. For example: + +```ruby +class CategoryHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :products, Array[ProductHash] +end + +class ProductHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :categories, Array[CategoriesHash] +end +``` + +This will fail with a `NameError` for `CategoryHash::ProductHash` because `ProductHash` is not defined at the point that `coerce_key` is happening for `CategoryHash`. + +To work around this, you can use a coercion proc. For example, you could do: + +```ruby +class CategoryHash < Hash + # ... + coerce_key :products, ->(value) do + return value.map { |v| ProductHash.new(v) } if value.respond_to?(:map) + + ProductHash.new(value) + end +end +``` + ### KeyConversion 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`. @@ -154,7 +189,7 @@ ```ruby Hashie.symbolize_keys! hash # => Symbolizes keys of hash. Hashie.symbolize_keys hash # => Returns a copy of hash with keys symbolized. -Hashie.stringify_keys hash # => Stringifies keys of hash. +Hashie.stringify_keys! hash # => Stringifies keys of hash. Hashie.stringify_keys hash # => Returns a copy of hash with keys stringified. ``` @@ -524,13 +559,58 @@ p.trick # => NoMethodError ``` +### Dash Extension: PropertyTranslation + +The `Hashie::Extensions::Dash::PropertyTranslation` mixin extends a Dash with +the ability to remap keys from a source hash. + +### Example from inconsistent APIs + +Property translation is useful when you need to read data from another +application -- such as a Java API -- where the keys are named differently from +Ruby conventions. + +```ruby +class PersonHash < Hashie::Dash + include Hashie::Extensions::Dash::PropertyTranslation + + property :first_name, from: :firstName + property :last_name, from: :lastName + property :first_name, from: :f_name + property :last_name, from: :l_name +end + +person = PersonHash.new(firstName: 'Michael', l_name: 'Bleigh') +person[:first_name] #=> 'Michael' +person[:last_name] #=> 'Bleigh +``` + +### Example using translation lambdas + +You can also use a lambda to translate the value. This is particularly useful +when you want to ensure the type of data you're wrapping. + +```ruby +class DataModelHash < Hashie::Dash + include Hashie::Extensions::Dash::PropertyTranslation + + property :id, transform_with: ->(value) { value.to_i } + property :created_at, from: :created, with: ->(value) { Time.parse(value) } +end + +model = DataModelHash.new(id: '123', created: '2014-04-25 22:35:28') +model.id.class #=> Fixnum +model.created_at.class #=> Time +``` + ### Mash and Rails 4 Strong Parameters -To enable compatibility with Rails 4 use the [hashie_rails](http://rubygems.org/gems/hashie_rails) gem. +To enable compatibility with Rails 4 use the [hashie-forbidden_attributes](https://github.com/Maxim-Filimonov/hashie-forbidden_attributes) gem. ## Trash -A Trash is a Dash that allows you to translate keys on initialization. It is used like so: +A Trash is a Dash that allows you to translate keys on initialization. It mixes +in the PropertyTranslation mixin by default and is used like so: ```ruby class Person < Hashie::Trash Files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie/extensions/dash/property_translation.rb new/lib/hashie/extensions/dash/property_translation.rb --- old/lib/hashie/extensions/dash/property_translation.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/hashie/extensions/dash/property_translation.rb 2015-06-02 15:48:43.000000000 +0200 @@ -0,0 +1,167 @@ +module Hashie + module Extensions + module Dash + # Extends a Dash with the ability to remap keys from a source hash. + # + # Property translation is useful when you need to read data from another + # application -- such as a Java API -- where the keys are named + # differently from Ruby conventions. + # + # == Example from inconsistent APIs + # + # class PersonHash < Hashie::Dash + # include Hashie::Extensions::Dash::PropertyTranslation + # + # property :first_name, from :firstName + # property :last_name, from: :lastName + # property :first_name, from: :f_name + # property :last_name, from: :l_name + # end + # + # person = PersonHash.new(firstName: 'Michael', l_name: 'Bleigh') + # person[:first_name] #=> 'Michael' + # person[:last_name] #=> 'Bleigh' + # + # You can also use a lambda to translate the value. This is particularly + # useful when you want to ensure the type of data you're wrapping. + # + # == Example using translation lambdas + # + # class DataModelHash < Hashie::Dash + # include Hashie::Extensions::Dash::PropertyTranslation + # + # property :id, transform_with: ->(value) { value.to_i } + # property :created_at, from: :created, with: ->(value) { Time.parse(value) } + # end + # + # model = DataModelHash.new(id: '123', created: '2014-04-25 22:35:28') + # model.id.class #=> Fixnum + # model.created_at.class #=> Time + module PropertyTranslation + def self.included(base) + base.instance_variable_set(:@transforms, {}) + base.instance_variable_set(:@translations_hash, {}) + base.extend(ClassMethods) + base.send(:include, InstanceMethods) + end + + module ClassMethods + attr_reader :transforms, :translations_hash + + # Ensures that any inheriting classes maintain their translations. + # + # * <tt>:default</tt> - The class inheriting the translations. + def inherited(klass) + super + klass.instance_variable_set(:@transforms, transforms.dup) + klass.instance_variable_set(:@translations_hash, translations_hash.dup) + end + + def permitted_input_keys + @permitted_input_keys ||= properties.map { |property| inverse_translations.fetch property, property } + end + + # Defines a property on the Trash. Options are as follows: + # + # * <tt>:default</tt> - Specify a default value for this property, to be + # returned before a value is set on the property in a new Dash. + # * <tt>:from</tt> - Specify the original key name that will be write only. + # * <tt>:with</tt> - Specify a lambda to be used to convert value. + # * <tt>:transform_with</tt> - Specify a lambda to be used to convert value + # without using the :from option. It transform the property itself. + def property(property_name, options = {}) + super + + options[:from] = options[:from] if options[:from] + + if options[:from] + if property_name == options[:from] + fail ArgumentError, "Property name (#{property_name}) and :from option must not be the same" + end + + translations_hash[options[:from]] ||= {} + translations_hash[options[:from]][property_name] = options[:with] || options[:transform_with] + + define_method "#{options[:from]}=" do |val| + self.class.translations_hash[options[:from]].each do |name, with| + self[name] = with.respond_to?(:call) ? with.call(val) : val + end + end + else + if options[:transform_with].respond_to? :call + transforms[property_name] = options[:transform_with] + end + end + end + + def transformed_property(property_name, value) + transforms[property_name].call(value) + end + + def transformation_exists?(name) + transforms.key? name + end + + def translation_exists?(name) + translations_hash.key? name + end + + def translations + @translations ||= {}.tap do |h| + translations_hash.each do |(property_name, property_translations)| + if property_translations.size > 1 + h[property_name] = property_translations.keys + else + h[property_name] = property_translations.keys.first + end + end + end + end + + def inverse_translations + @inverse_translations ||= {}.tap do |h| + translations_hash.each do |(property_name, property_translations)| + property_translations.keys.each do |k| + h[k] = property_name + end + end + end + end + end + + module InstanceMethods + # Sets a value on the Dash in a Hash-like way. + # + # Note: Only works on pre-existing properties. + def []=(property, value) + if self.class.translation_exists? property + send("#{property}=", value) + elsif self.class.transformation_exists? property + super property, self.class.transformed_property(property, value) + elsif property_exists? property + super + end + end + + # Deletes any keys that have a translation + def initialize_attributes(attributes) + return unless attributes + attributes_copy = attributes.dup.delete_if do |k, v| + if self.class.translations_hash.include?(k) + self[k] = v + true + end + end + super attributes_copy + end + + # Raises an NoMethodError if the property doesn't exist + def property_exists?(property) + fail_no_property_error!(property) unless self.class.property?(property) + true + end + end + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie/extensions/deep_find.rb new/lib/hashie/extensions/deep_find.rb --- old/lib/hashie/extensions/deep_find.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/lib/hashie/extensions/deep_find.rb 2015-06-02 15:48:43.000000000 +0200 @@ -5,7 +5,16 @@ # a key and returns the first occurrence of the key. # # options = {user: {location: {address: '123 Street'}}} + # options.extend(Hashie::Extensions::DeepFind) # options.deep_find(:address) # => '123 Street' + # + # class MyHash < Hash + # include Hashie::Extensions::DeepFind + # end + # + # my_hash = MyHash.new + # my_hash[:user] = {location: {address: '123 Street'}} + # my_hash.deep_find(:address) # => '123 Street' def deep_find(key) _deep_find(key) end @@ -16,7 +25,16 @@ # a key and returns all occurrences of the key. # # options = {users: [{location: {address: '123 Street'}}, {location: {address: '234 Street'}}]} + # options.extend(Hashie::Extensions::DeepFind) # options.deep_find_all(:address) # => ['123 Street', '234 Street'] + # + # class MyHash < Hash + # include Hashie::Extensions::DeepFind + # end + # + # my_hash = MyHash.new + # my_hash[:users] = [{location: {address: '123 Street'}}, {location: {address: '234 Street'}}] + # my_hash.deep_find_all(:address) # => ['123 Street', '234 Street'] def deep_find_all(key) matches = _deep_find_all(key) matches.empty? ? nil : matches diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie/mash.rb new/lib/hashie/mash.rb --- old/lib/hashie/mash.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/lib/hashie/mash.rb 2015-06-02 15:48:43.000000000 +0200 @@ -92,14 +92,6 @@ class << self; alias_method :[], :new; end - def id #:nodoc: - self['id'] - end - - def type #:nodoc: - self['type'] - end - alias_method :regular_reader, :[] alias_method :regular_writer, :[]= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie/trash.rb new/lib/hashie/trash.rb --- old/lib/hashie/trash.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/lib/hashie/trash.rb 2015-06-02 15:48:43.000000000 +0200 @@ -1,4 +1,5 @@ require 'hashie/dash' +require 'hashie/extensions/dash/property_translation' module Hashie # A Trash is a 'translated' Dash where the keys can be remapped from a source @@ -8,122 +9,6 @@ # such as a Java api, where the keys are named differently from how we would # in Ruby. class Trash < Dash - # Defines a property on the Trash. Options are as follows: - # - # * <tt>:default</tt> - Specify a default value for this property, to be - # returned before a value is set on the property in a new Dash. - # * <tt>:from</tt> - Specify the original key name that will be write only. - # * <tt>:with</tt> - Specify a lambda to be used to convert value. - # * <tt>:transform_with</tt> - Specify a lambda to be used to convert value - # without using the :from option. It transform the property itself. - def self.property(property_name, options = {}) - super - - options[:from] = options[:from] if options[:from] - - if options[:from] - if property_name == options[:from] - fail ArgumentError, "Property name (#{property_name}) and :from option must not be the same" - end - - translations_hash[options[:from]] ||= {} - translations_hash[options[:from]][property_name] = options[:with] || options[:transform_with] - - define_method "#{options[:from]}=" do |val| - self.class.translations_hash[options[:from]].each do |name, with| - self[name] = with.respond_to?(:call) ? with.call(val) : val - end - end - else - if options[:transform_with].respond_to? :call - transforms[property_name] = options[:transform_with] - end - end - end - - class << self - attr_reader :transforms, :translations_hash - end - instance_variable_set('@transforms', {}) - instance_variable_set('@translations_hash', {}) - - def self.inherited(klass) - super - klass.instance_variable_set('@transforms', transforms.dup) - klass.instance_variable_set('@translations_hash', translations_hash.dup) - end - - # Set a value on the Dash in a Hash-like way. Only works - # on pre-existing properties. - def []=(property, value) - if self.class.translation_exists? property - send("#{property}=", value) - elsif self.class.transformation_exists? property - super property, self.class.transformed_property(property, value) - elsif property_exists? property - super - end - end - - def self.transformed_property(property_name, value) - transforms[property_name].call(value) - end - - def self.translation_exists?(name) - translations_hash.key? name - end - - def self.transformation_exists?(name) - transforms.key? name - end - - def self.permitted_input_keys - @permitted_input_keys ||= properties.map { |property| inverse_translations.fetch property, property } - end - - private - - def self.translations - @translations ||= begin - h = {} - translations_hash.each do |(property_name, property_translations)| - h[property_name] = property_translations.size > 1 ? property_translations.keys : property_translations.keys.first - end - h - end - end - - def self.inverse_translations - @inverse_translations ||= begin - h = {} - translations_hash.each do |(property_name, property_translations)| - property_translations.keys.each do |k| - h[k] = property_name - end - end - h - end - end - - # Raises an NoMethodError if the property doesn't exist - # - def property_exists?(property) - fail_no_property_error!(property) unless self.class.property?(property) - true - end - - private - - # Deletes any keys that have a translation - def initialize_attributes(attributes) - return unless attributes - attributes_copy = attributes.dup.delete_if do |k, v| - if self.class.translations_hash.include?(k) - self[k] = v - true - end - end - super attributes_copy - end + include Hashie::Extensions::Dash::PropertyTranslation end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie/version.rb new/lib/hashie/version.rb --- old/lib/hashie/version.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/lib/hashie/version.rb 2015-06-02 15:48:43.000000000 +0200 @@ -1,3 +1,3 @@ module Hashie - VERSION = '3.4.1' + VERSION = '3.4.2' end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/hashie.rb new/lib/hashie.rb --- old/lib/hashie.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/lib/hashie.rb 2015-06-02 15:48:43.000000000 +0200 @@ -33,6 +33,7 @@ module Dash autoload :IndifferentAccess, 'hashie/extensions/dash/indifferent_access' + autoload :PropertyTranslation, 'hashie/extensions/dash/property_translation' end module Mash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-03-31 17:04:55.000000000 +0200 +++ new/metadata 2015-06-02 15:48:43.000000000 +0200 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: hashie version: !ruby/object:Gem::Version - version: 3.4.1 + version: 3.4.2 platform: ruby authors: - Michael Bleigh @@ -9,7 +9,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2015-03-31 00:00:00.000000000 Z +date: 2015-06-02 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rake @@ -60,6 +60,7 @@ - lib/hashie/dash.rb - lib/hashie/extensions/coercion.rb - lib/hashie/extensions/dash/indifferent_access.rb +- lib/hashie/extensions/dash/property_translation.rb - lib/hashie/extensions/deep_fetch.rb - lib/hashie/extensions/deep_find.rb - lib/hashie/extensions/deep_locate.rb @@ -105,6 +106,7 @@ - spec/hashie/version_spec.rb - spec/spec_helper.rb - spec/support/module_context.rb +- spec/support/ruby_version.rb homepage: https://github.com/intridea/hashie licenses: - MIT @@ -125,34 +127,35 @@ version: '0' requirements: [] rubyforge_project: -rubygems_version: 2.2.2 +rubygems_version: 2.4.5 signing_key: specification_version: 4 summary: Your friendly neighborhood hash library. test_files: -- spec/hashie/clash_spec.rb +- spec/spec_helper.rb +- spec/support/ruby_version.rb +- spec/support/module_context.rb +- spec/hashie/parsers/yaml_erb_parser_spec.rb +- spec/hashie/version_spec.rb +- spec/hashie/rash_spec.rb - spec/hashie/dash_spec.rb -- spec/hashie/extensions/autoload_spec.rb -- spec/hashie/extensions/coercion_spec.rb -- spec/hashie/extensions/dash/indifferent_access_spec.rb +- spec/hashie/hash_spec.rb +- spec/hashie/clash_spec.rb +- spec/hashie/mash_spec.rb +- spec/hashie/trash_spec.rb - spec/hashie/extensions/deep_fetch_spec.rb -- spec/hashie/extensions/deep_find_spec.rb +- spec/hashie/extensions/method_access_spec.rb +- spec/hashie/extensions/key_conversion_spec.rb - spec/hashie/extensions/deep_locate_spec.rb - spec/hashie/extensions/deep_merge_spec.rb -- spec/hashie/extensions/ignore_undeclared_spec.rb -- spec/hashie/extensions/indifferent_access_spec.rb - spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb -- spec/hashie/extensions/key_conversion_spec.rb +- spec/hashie/extensions/symbolize_keys_spec.rb - spec/hashie/extensions/mash/safe_assignment_spec.rb -- spec/hashie/extensions/merge_initializer_spec.rb -- spec/hashie/extensions/method_access_spec.rb +- spec/hashie/extensions/deep_find_spec.rb +- spec/hashie/extensions/ignore_undeclared_spec.rb +- spec/hashie/extensions/autoload_spec.rb - spec/hashie/extensions/stringify_keys_spec.rb -- spec/hashie/extensions/symbolize_keys_spec.rb -- spec/hashie/hash_spec.rb -- spec/hashie/mash_spec.rb -- spec/hashie/parsers/yaml_erb_parser_spec.rb -- spec/hashie/rash_spec.rb -- spec/hashie/trash_spec.rb -- spec/hashie/version_spec.rb -- spec/spec_helper.rb -- spec/support/module_context.rb +- spec/hashie/extensions/indifferent_access_spec.rb +- spec/hashie/extensions/coercion_spec.rb +- spec/hashie/extensions/merge_initializer_spec.rb +- spec/hashie/extensions/dash/indifferent_access_spec.rb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/hashie/extensions/coercion_spec.rb new/spec/hashie/extensions/coercion_spec.rb --- old/spec/hashie/extensions/coercion_spec.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/spec/hashie/extensions/coercion_spec.rb 2015-06-02 15:48:43.000000000 +0200 @@ -437,6 +437,67 @@ expect(MyOwnBase.key_coercions).to eq({}) end end + + context 'when using circular coercion' do + context 'with a proc on one side' do + class CategoryHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :products, lambda { |value| + return value.map { |v| ProductHash.new(v) } if value.respond_to?(:map) + + ProductHash.new(v) + } + end + + class ProductHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :categories, Array[CategoryHash] + end + + let(:category) { CategoryHash.new(type: 'rubygem', products: [Hashie::Mash.new(name: 'Hashie')]) } + let(:product) { ProductHash.new(name: 'Hashie', categories: [Hashie::Mash.new(type: 'rubygem')]) } + + it 'coerces CategoryHash[:products] correctly' do + expected = [ProductHash] + actual = category[:products].map(&:class) + + expect(actual).to eq(expected) + end + + it 'coerces ProductHash[:categories] correctly' do + expected = [CategoryHash] + actual = product[:categories].map(&:class) + + expect(actual).to eq(expected) + end + end + + context 'without a proc on either side' do + it 'fails with a NameError since the other class is not defined yet' do + attempted_code = lambda do + class AnotherCategoryHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :products, Array[AnotherProductHash] + end + + class AnotherProductHash < Hash + include Hashie::Extensions::Coercion + include Hashie::Extensions::MergeInitializer + + coerce_key :categories, Array[AnotherCategoryHash] + end + end + + expect { attempted_code.call }.to raise_error(NameError) + end + end + end end describe '#coerce_value' do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/hashie/mash_spec.rb new/spec/hashie/mash_spec.rb --- old/spec/hashie/mash_spec.rb 2015-03-31 17:04:55.000000000 +0200 +++ new/spec/hashie/mash_spec.rb 2015-06-02 15:48:43.000000000 +0200 @@ -1,5 +1,6 @@ require 'spec_helper' require 'delegate' +require 'support/ruby_version' describe Hashie::Mash do subject { Hashie::Mash.new } @@ -346,6 +347,11 @@ it 'responds to a set key with a suffix' do %w(= ? ! _).each do |suffix| expect(subject).to be_respond_to(:"abc#{suffix}") + end + end + + it 'is able to access the suffixed key as a method' do + %w(= ? ! _).each do |suffix| expect(subject.method(:"abc#{suffix}")).to_not be_nil end end @@ -353,6 +359,16 @@ it 'responds to an unknown key with a suffix' do %w(= ? ! _).each do |suffix| expect(subject).to be_respond_to(:"xyz#{suffix}") + end + end + + it 'is able to access an unknown suffixed key as a method' do + # See https://github.com/intridea/hashie/pull/285 for more information + if mri22? + pending 'Bug in MRI 2.2.x means this behavior is broken in those versions' + end + + %w(= ? ! _).each do |suffix| expect(subject.method(:"xyz#{suffix}")).to_not be_nil end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/support/ruby_version.rb new/spec/support/ruby_version.rb --- old/spec/support/ruby_version.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/spec/support/ruby_version.rb 2015-06-02 15:48:43.000000000 +0200 @@ -0,0 +1,10 @@ +def mri22? + ruby_version.start_with?('ruby_2.2') +end + +def ruby_version + interpreter = Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE + version = Object.const_defined?(:RUBY_VERSION) && RUBY_VERSION + + "#{interpreter}_#{version}" +end