Compare commits

...

13 Commits

Author SHA1 Message Date
Daniel (dB.) Doubrovkine 639859e642
Merge pull request #565 from hashie/dependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2022-06-27 12:26:01 -03:00
dependabot[bot] 9601a8a864
Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-24 20:48:22 +00:00
Daniel (dB.) Doubrovkine 7ff4741d78
Merge pull request #564 from petergoldstein/feature/add_dependabot_for_github_actions
Add dependabot for GitHub Actions
2022-06-24 16:48:04 -04:00
Peter Goldstein 9c6334c675 Add dependabot for GitHub Actions
This will ensure that GitHub Actions stay up to date.  As the checkout action is currently out of date, Dependabot should open a PR to update it after this PR is merged.
2022-06-23 23:28:10 -07:00
Daniel Doubrovkine (dB.) c297afb13b
Merge pull request #561 from dblock/ci-all-branches
Run CI on all branches.
2022-03-26 12:57:21 -04:00
dblock 92dc0845c5
Fix: TOC. 2022-03-26 12:55:53 -04:00
dblock f326db495a
Use a public PAT. 2022-03-26 12:49:00 -04:00
dblock 7a9c4a7d41
Move danger into its own workflow file. 2022-03-25 10:03:09 -04:00
dblock 43b476a342
Run CI on all branches. 2022-03-24 12:42:36 -04:00
Peter Goldstein 3e57eb531f
Add Ruby 3.1 to CI (#558)
* Add Ruby 3.1 to CI

Update Rubocop for recent Rubies
Disable Rubocop run for Rubies before Ruby 2.4
Quote '3.0' in the CI configuration to ensure it loads a 3.0.x Ruby
Set RUBYOPT="--disable_error_highlight" so Ruby 3.1 error matchers pass

* Add CHANGELOG.md entry

* Re-add deleted line from CHANGELOG.md

* Set minimum supported Ruby version to 2.4.

Remove a number of code bits designed to support Rubies below version 2.4

* Bump version.  Remove unneeded require from Gemfile.  Add require to spec/support file
2022-01-27 18:59:24 -08:00
Daniel Doubrovkine (dB.) 4dc015eb52
Merge pull request #557 from njakobsen/patch-1
Include example of Dash's lazy evaluation feature
2021-12-11 04:08:12 +00:00
Nicholas Jakobsen 39a1acccf2
Include example of Dash's lazy evaluation feature
This was added in d20eed6540 but was never documented.
2021-12-09 16:06:45 -08:00
dblock e201d4006d
Preparing for next development iteration, 5.0.1. 2021-11-08 14:47:35 -05:00
19 changed files with 200 additions and 182 deletions

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

21
.github/workflows/danger.yml vendored Normal file
View File

@ -0,0 +1,21 @@
---
name: danger
on: [pull_request]
jobs:
danger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
- name: Run Danger
run: |
bundle install
# the personal token is public, this is ok, base64 encode to avoid tripping Github
TOKEN=$(echo -n NWY1ZmM5MzEyMzNlYWY4OTZiOGU3MmI3MWQ3Mzk0MzgxMWE4OGVmYwo= | base64 --decode)
DANGER_GITHUB_API_TOKEN=$TOKEN bundle exec danger --verbose

View File

@ -1,38 +1,11 @@
name: CI
on:
push:
branches:
- master
pull_request:
branches:
- master
on: [push, pull_request]
jobs:
danger:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true
- uses: MeilCli/danger-action@v5
with:
danger_file: Dangerfile
danger_id: danger-pr
install_path: vendor/bundle
plugins_file: Gemfile
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.github_token }}
integration-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
@ -52,16 +25,14 @@ jobs:
fail-fast: false
matrix:
ruby:
- 3.0
- 2.7
- 2.6
- 2.5
- 2.4
- 2.3
- 2.2
- 2.1
- '3.1'
- '3.0'
- '2.7'
- '2.6'
- '2.5'
- '2.4'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
@ -70,6 +41,8 @@ jobs:
- name: Install dependencies
run: bundle install --jobs 4 --retry 3
- name: Run tests
env:
RUBYOPT: "--disable-error_highlight"
run: bundle exec rake
test-jruby:
@ -83,7 +56,7 @@ jobs:
jruby:
- jruby
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:

View File

@ -9,7 +9,7 @@ AllCops:
inherit_from: .rubocop_todo.yml
# Disabled until we can use the squiggly heredoc (after deprecating Ruby <2.3)
Layout/IndentHeredoc:
Layout/HeredocIndentation:
Enabled: false
Metrics/ClassLength:
@ -43,3 +43,6 @@ Naming/FileName:
# boolean casting that we do.
Style/DoubleNegation:
Enabled: false
Style/HashSyntax:
Enabled: false

View File

@ -6,6 +6,39 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Any violations of this scheme are considered to be bugs.
## [Unreleased][unreleased]
[unreleased]: https://github.com/hashie/hashie/compare/v5.0.0...master
### Added
* Your contribution here.
### Changed
* Your contribution here.
* [#558](https://github.com/hashie/hashie/pull/558): Test with Ruby 3.1 - [@petergoldstein](https://github.com/petergoldstein).
### Deprecated
* Your contribution here.
### Removed
* Your contribution here.
### Fixed
* Your contribution here.
### Security
* Your contribution here.
### Miscellaneous
* Your contribution here.
## [5.0.0] - 2021-11-08
[5.0.0]: https://github.com/hashie/hashie/compare/v4.1.0...v5.0.0

14
Gemfile
View File

@ -9,20 +9,12 @@ group :development do
gem 'guard-rspec', '~> 4.3.1', require: false
gem 'guard-yield', '~> 0.1.0', require: false
gem 'pry'
gem 'pry-stack_explorer', platforms: %i[ruby_19 ruby_20 ruby_21]
gem 'rubocop', '0.52.1'
gem 'rubocop', '~> 1.0'
group :test do
# ActiveSupport required to test compatibility with ActiveSupport Core Extensions.
# rubocop:disable Bundler/DuplicatedGem
require File.expand_path('../lib/hashie/extensions/ruby_version', __FILE__)
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
gem 'activesupport', '~> 5.x', require: false
else
gem 'activesupport', '~> 4.x', require: false
end
# rubocop:enable Bundler/DuplicatedGem
gem 'activesupport', '~> 5.x', require: false
gem 'rake'
gem 'rspec', '~> 3'
gem 'rspec-pending_for', '~> 0.1'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require_relative 'spec/support/integration_specs'
run_all = lambda do |*|

View File

@ -2,55 +2,53 @@
[![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)
[![Gem Version](http://img.shields.io/gem/v/hashie.svg)](http://badge.fury.io/rb/hashie)
[![Build Status](https://github.com/hashie/hashie/actions/workflows/main.yml/badge.svg)](https://github.com/hashie/hashie/actions/workflows/main.yml)
[![Build Status](https://github.com/hashie/hashie/actions/workflows/test.yml/badge.svg)](https://github.com/hashie/hashie/actions/workflows/test.yml)
[![eierlegende Wollmilchsau](./mascot.svg)](#mascot) Hashie is a growing collection of tools that extend Hashes and make them more useful.
# Table of Contents
- [Hashie](#hashie)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Stable Release](#stable-release)
- [Hash Extensions](#hash-extensions)
- [Logging](#logging)
- [Coercion](#coercion)
- [Coercing Collections](#coercing-collections)
- [Coercing Hashes](#coercing-hashes)
- [Coercing Core Types](#coercing-core-types)
- [Coercion Proc](#coercion-proc)
- [A note on circular coercion](#a-note-on-circular-coercion)
- [KeyConversion](#keyconversion)
- [MergeInitializer](#mergeinitializer)
- [MethodAccess](#methodaccess)
- [MethodAccessWithOverride](#methodaccesswithoverride)
- [MethodOverridingInitializer](#methodoverridinginitializer)
- [IndifferentAccess](#indifferentaccess)
- [IgnoreUndeclared](#ignoreundeclared)
- [DeepMerge](#deepmerge)
- [DeepFetch](#deepfetch)
- [DeepFind](#deepfind)
- [DeepLocate](#deeplocate)
- [StrictKeyAccess](#strictkeyaccess)
- [Mash](#mash)
- [KeepOriginalKeys](#keeporiginalkeys)
- [PermissiveRespondTo](#permissiverespondto)
- [SafeAssignment](#safeassignment)
- [SymbolizeKeys](#symbolizekeys)
- [DefineAccessors](#defineaccessors)
- [Dash](#dash)
- [Potential Gotchas](#potential-gotchas)
- [PropertyTranslation](#propertytranslation)
- [Mash and Rails 4 Strong Parameters](#mash-and-rails-4-strong-parameters)
- [Coercion](#coercion-1)
- [PredefinedValues](#predefinedvalues)
- [Trash](#trash)
- [Clash](#clash)
- [Rash](#rash)
- [Auto-Optimized](#auto-optimized)
- [Mascot](#mascot)
- [Contributing](#contributing)
- [Copyright](#copyright)
- [Installation](#installation)
- [Stable Release](#stable-release)
- [Hash Extensions](#hash-extensions)
- [Logging](#logging)
- [Coercion](#coercion)
- [Coercing Collections](#coercing-collections)
- [Coercing Hashes](#coercing-hashes)
- [Coercing Core Types](#coercing-core-types)
- [Coercion Proc](#coercion-proc)
- [A note on circular coercion](#a-note-on-circular-coercion)
- [KeyConversion](#keyconversion)
- [MergeInitializer](#mergeinitializer)
- [MethodAccess](#methodaccess)
- [MethodAccessWithOverride](#methodaccesswithoverride)
- [MethodOverridingInitializer](#methodoverridinginitializer)
- [IndifferentAccess](#indifferentaccess)
- [IgnoreUndeclared](#ignoreundeclared)
- [DeepMerge](#deepmerge)
- [DeepFetch](#deepfetch)
- [DeepFind](#deepfind)
- [DeepLocate](#deeplocate)
- [StrictKeyAccess](#strictkeyaccess)
- [Mash](#mash)
- [KeepOriginalKeys](#keeporiginalkeys)
- [PermissiveRespondTo](#permissiverespondto)
- [SafeAssignment](#safeassignment)
- [SymbolizeKeys](#symbolizekeys)
- [DefineAccessors](#defineaccessors)
- [Dash](#dash)
- [Potential Gotchas](#potential-gotchas)
- [PropertyTranslation](#propertytranslation)
- [Mash and Rails 4 Strong Parameters](#mash-and-rails-4-strong-parameters)
- [Coercion](#coercion-1)
- [PredefinedValues](#predefinedvalues)
- [Trash](#trash)
- [Clash](#clash)
- [Rash](#rash)
- [Auto-Optimized](#auto-optimized)
- [Mascot](#mascot)
- [Contributing](#contributing)
- [Copyright](#copyright)
## Installation
@ -62,7 +60,8 @@ $ gem install hashie
## Stable Release
You're reading the documentation for the stable release of Hashie, v5.0.0.
You're reading the documentation for the next release of Hashie, which should be 5.0.1.
The current stable release is [5.0.0](https://github.com/hashie/hashie/blob/v5.0.0/README.md).
## Hash Extensions
@ -811,7 +810,7 @@ mash = ::Hashie::Mash.new.with_accessors!
## Dash
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.
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. A property with a proc value will be evaluated lazily upon retrieval.
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.
@ -823,6 +822,7 @@ class Person < Hashie::Dash
property :phone, required: -> { email.nil? }, message: 'is required if email is not set.'
property :pants, required: :weekday?, message: 'are only required on weekdays.'
property :occupation, default: 'Rubyist'
property :genome
def weekday?
[ Time.now.saturday?, Time.now.sunday? ].none?
@ -847,6 +847,8 @@ p.occupation # => 'Evil'
p.name # => 'Trudy'
p.update_attributes!(occupation: nil)
p.occupation # => 'Rubyist'
p.genome = -> { Genome.sequence } # Some expensive operation
p.genome # => 'GATTACA'
```
Properties defined as symbols are not the same thing as properties defined as strings.

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rubygems'
require 'bundler'
Bundler.setup
@ -16,6 +18,7 @@ RuboCop::RakeTask.new(:rubocop)
require_relative 'spec/support/integration_specs'
task :integration_specs do
next if ENV['CI']
status_codes = []
handler = lambda do |status_code|
status_codes << status_code unless status_code.zero?

View File

@ -1,4 +1,5 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/setup'
require 'hashie'

View File

@ -24,5 +24,7 @@ Gem::Specification.new do |gem|
}
end
gem.required_ruby_version = '>= 2.4'
gem.add_development_dependency 'bundler'
end

View File

@ -17,14 +17,7 @@ module Hashie
}.freeze
ABSTRACT_CORE_TYPES =
if RubyVersion.new(RUBY_VERSION) >= RubyVersion.new('2.4.0')
{ Numeric => [Integer, Float, Complex, Rational] }
else
{
Integer => [Fixnum, Bignum],
Numeric => [Fixnum, Bignum, Float, Complex, Rational]
}
end
{ Numeric => [Integer, Float, Complex, Rational] }
def self.included(base)
base.send :include, InstanceMethods

View File

@ -322,22 +322,18 @@ module Hashie
self.class.new(other_hash).merge(self)
end
with_minimum_ruby('2.3.0') do
def dig(*keys)
super(*keys.map { |key| convert_key(key) })
end
def dig(*keys)
super(*keys.map { |key| convert_key(key) })
end
with_minimum_ruby('2.4.0') do
def transform_values(&blk)
self.class.new(super(&blk))
end
def transform_values(&blk)
self.class.new(super(&blk))
end
# Returns a new instance of the class it was called on, with nil values
# removed.
def compact
self.class.new(super)
end
# Returns a new instance of the class it was called on, with nil values
# removed.
def compact
self.class.new(super)
end
with_minimum_ruby('2.5.0') do

View File

@ -1,3 +1,3 @@
module Hashie
VERSION = '5.0.0'.freeze
VERSION = '5.1.0'.freeze
end

View File

@ -1,28 +1,26 @@
require 'spec_helper'
describe Array do
with_minimum_ruby('2.3.0') do
describe '#dig' do
let(:array) { Hashie::Array.new(%i[a b c]) }
describe '#dig' do
let(:array) { Hashie::Array.new(%i[a b c]) }
it 'works with a string index' do
expect(array.dig('0')).to eq(:a)
it 'works with a string index' do
expect(array.dig('0')).to eq(:a)
end
it 'works with a numeric index' do
expect(array.dig(1)).to eq(:b)
end
context 'when array is empty' do
let(:array) { Hashie::Array.new([]) }
it 'works with a first numeric and next string index' do
expect(array.dig(0, 'hello')).to eq(nil)
end
it 'works with a numeric index' do
expect(array.dig(1)).to eq(:b)
end
context 'when array is empty' do
let(:array) { Hashie::Array.new([]) }
it 'works with a first numeric and next string index' do
expect(array.dig(0, 'hello')).to eq(nil)
end
it 'throws an error with first string and next numeric index' do
expect { array.dig('hello', 0) }.to raise_error(TypeError)
end
it 'throws an error with first string and next numeric index' do
expect { array.dig('hello', 0) }.to raise_error(TypeError)
end
end
end

View File

@ -563,13 +563,7 @@ describe Hashie::Extensions::Coercion do
end
it 'raises a CoercionError when coercion is not possible' do
type =
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum
end
type = Integer
subject.coerce_value type, Symbol
expect { instance[:hi] = 1 }.to raise_error(
@ -578,13 +572,7 @@ describe Hashie::Extensions::Coercion do
end
it 'coerces Integer to String' do
type =
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum
end
type = Integer
subject.coerce_value type, String

View File

@ -649,8 +649,7 @@ describe Hashie::Mash do
context 'when key does not exist' do
it 'raises KeyError' do
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError
expect { mash.fetch(:two) }.to raise_error(error)
expect { mash.fetch(:two) }.to raise_error(KeyError)
end
context 'with default value given' do
@ -980,44 +979,40 @@ describe Hashie::Mash do
end
end
with_minimum_ruby('2.3.0') do
describe '#dig' do
subject { described_class.new(a: { b: 1 }) }
describe '#dig' do
subject { described_class.new(a: { b: 1 }) }
it 'accepts both string and symbol as key' do
expect(subject.dig(:a, :b)).to eq(1)
expect(subject.dig('a', 'b')).to eq(1)
end
it 'accepts both string and symbol as key' do
expect(subject.dig(:a, :b)).to eq(1)
expect(subject.dig('a', 'b')).to eq(1)
end
context 'when the Mash wraps a Hashie::Array' do
it 'handles digging into an array' do
mash = described_class.new(alphabet: { first_three: Hashie::Array['a', 'b', 'c'] })
context 'when the Mash wraps a Hashie::Array' do
it 'handles digging into an array' do
mash = described_class.new(alphabet: { first_three: Hashie::Array['a', 'b', 'c'] })
expect(mash.dig(:alphabet, :first_three, 0)).to eq 'a'
end
expect(mash.dig(:alphabet, :first_three, 0)).to eq 'a'
end
end
end
with_minimum_ruby('2.4.0') do
describe '#transform_values' do
subject(:mash) { described_class.new(a: 1) }
describe '#transform_values' do
subject(:mash) { described_class.new(a: 1) }
it 'returns a Hashie::Mash' do
expect(mash.transform_values(&:to_s)).to be_kind_of(described_class)
end
it 'returns a Hashie::Mash' do
expect(mash.transform_values(&:to_s)).to be_kind_of(described_class)
end
it 'transforms the value' do
expect(mash.transform_values(&:to_s).a).to eql('1')
end
it 'transforms the value' do
expect(mash.transform_values(&:to_s).a).to eql('1')
end
context 'when using with subclass' do
let(:subclass) { Class.new(Hashie::Mash) }
subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } }
context 'when using with subclass' do
let(:subclass) { Class.new(Hashie::Mash) }
subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } }
it 'creates an instance of subclass' do
expect(sub_mash).to be_kind_of(subclass)
end
it 'creates an instance of subclass' do
expect(sub_mash).to be_kind_of(subclass)
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :perf do
task :setup do
require 'omniauth'
@ -12,6 +14,7 @@ namespace :perf do
def call_app(path = ENV['GET_PATH'] || '/')
result = @app.get(path)
raise "Did not succeed #{result.body}" unless result.status == 200
result
end
end

View File

@ -1,10 +1,17 @@
require File.expand_path('../../../lib/hashie/extensions/ruby_version', __FILE__)
# Generates the bundle command for running an integration test
#
# @param [String] integration the integration folder to run
# @param [String] command the command to run
# @return [String]
def integration_command(integration, command)
"#{integration_gemfile(integration)} #{command}"
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('3.1.0')
ruby_opts = "RUBYOPT=--disable-error_highlight "
end
"#{ruby_opts}#{integration_gemfile(integration)} #{command}"
end
# Generates the Gemfile for an integration