Skip to content

Commit

Permalink
Merge pull request #482 from Dynamoid/run-ruby-3-0-and-rails-6-1-on-ci
Browse files Browse the repository at this point in the history
Support Ruby 3.0
  • Loading branch information
andrykonchin committed Jan 8, 2021
2 parents aaf2aea + 74d9351 commit 4e09761
Show file tree
Hide file tree
Showing 16 changed files with 100 additions and 41 deletions.
42 changes: 26 additions & 16 deletions .travis.yml
Expand Up @@ -6,33 +6,43 @@ rvm:
- ruby-2.4.6
- ruby-2.5.5
- ruby-2.6.3
- jruby-9.2.8.0
- ruby-2.7.0
- ruby-3.0.0
- jruby-9.2.14.0
gemfile:
- gemfiles/rails_4_2.gemfile
- gemfiles/rails_5_0.gemfile
- gemfiles/rails_5_1.gemfile
- gemfiles/rails_5_2.gemfile
- gemfiles/rails_5_2.gemfile
- gemfiles/rails_6_0.gemfile
- gemfiles/rails_6_1.gemfile

# https://docs.travis-ci.com/user/build-matrix
matrix:
include:
# Ruby 2.7
# Rails works with Ruby 2.7 only from Rails 5.0
- rvm: ruby-2.7.0
exclude:

# Rails 6.0 requires Ruby 2.5 and above
- rvm: ruby-2.3.8
gemfile: gemfiles/rails_6_0.gemfile
- rvm: ruby-2.4.6
gemfile: gemfiles/rails_6_0.gemfile

# Rails 6.1 requires Ruby 2.5 and above
- rvm: ruby-2.3.8
gemfile: gemfiles/rails_6_1.gemfile
- rvm: ruby-2.4.6
gemfile: gemfiles/rails_6_1.gemfile

# Rails supports Ruby 3 since 6.0 only so skip all the other versions
- rvm: ruby-3.0.0
gemfile: gemfiles/rails_4_2.gemfile
- rvm: ruby-3.0.0
gemfile: gemfiles/rails_5_0.gemfile
- rvm: ruby-2.7.0
- rvm: ruby-3.0.0
gemfile: gemfiles/rails_5_1.gemfile
- rvm: ruby-2.7.0
- rvm: ruby-3.0.0
gemfile: gemfiles/rails_5_2.gemfile

# Rails 6
# It requires Ruby 2.5 and above
- rvm: ruby-2.5.3
gemfile: gemfiles/rails_6_0.gemfile
- rvm: ruby-2.6.3
gemfile: gemfiles/rails_6_0.gemfile
- rvm: ruby-2.7.0
gemfile: gemfiles/rails_6_0.gemfile

### BUILD LIFECYCLE STEPS ###

Expand Down
15 changes: 14 additions & 1 deletion Appraisals
Expand Up @@ -2,6 +2,15 @@

appraise 'rails-4-2' do
gem 'activemodel', '~> 4.2.0'

# Add bigdecimal gem to support Ruby 2.7 and above:
# https://github.com/rails/rails/issues/34822

# Compatibility with Ruby versions:
# https://github.com/ruby/bigdecimal#which-version-should-you-select
#
# Actually bigdecimal 1.4.x works on all the Ruby versions till Ruby 3.0
gem 'bigdecimal', '~> 1.4.0', platform: :mri
end

appraise 'rails-5-0' do
Expand All @@ -17,5 +26,9 @@ appraise 'rails-5-2' do
end

appraise 'rails-6-0' do
gem 'activemodel', '6.0.0'
gem 'activemodel', '~> 6.0.0'
end

appraise 'rails-6-1' do
gem 'activemodel', '~> 6.1.0'
end
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -126,8 +126,8 @@ end
Dynamoid supports Ruby >= 2.3 and Rails >= 4.2.

Its compatibility is tested against following Ruby versions: 2.3, 2.4,
2.5, 2.6 and 2.7, JRuby 9.2.8.0 and against Rails versions: 4.2, 5.0, 5.1,
5.2 and 6.0.
2.5, 2.6, 2.7 and 3.0, JRuby 9.2.x and against Rails versions: 4.2, 5.0, 5.1,
5.2, 6.0 and 6.1.

## Setup

Expand Down Expand Up @@ -1362,12 +1362,12 @@ environment.

If you want to run all the specs that travis runs, use `bundle exec
wwtd`, but first you will need to setup all the rubies, for each of `%w(
2.0.0-p648 2.1.10 2.2.6 2.3.3 2.4.1 jruby-9.1.8.0 )`. When you run
2.3.8 2.4.6 2.5.5 2.6.3 2.7.0 3.0.0 9.2.14.0)`. When you run
`bundle exec wwtd` it will take care of starting and stopping the local
dynamodb instance.

```shell
rvm use 2.0.0-p648
rvm use 3.0.0
gem install rubygems-update
gem install bundler
bundle install
Expand Down
12 changes: 5 additions & 7 deletions gemfiles/rails_4_2.gemfile
@@ -1,11 +1,9 @@
# frozen_string_literal: true

# This file was generated by Appraisal

source 'https://rubygems.org'
source "https://rubygems.org"

gem 'activemodel', '~> 4.2.0'
gem 'nokogiri', '~> 1.6.8'
gem 'pry-byebug', platforms: :ruby
gem "pry-byebug", platforms: :ruby
gem "activemodel", "~> 4.2.0"
gem "bigdecimal", "~> 1.4.0", platform: :mri

gemspec path: '../'
gemspec path: "../"
2 changes: 1 addition & 1 deletion gemfiles/rails_6_0.gemfile
Expand Up @@ -4,7 +4,7 @@

source 'https://rubygems.org'

gem 'activemodel', '6.0.0'
gem 'activemodel', '~> 6.0.0'
gem 'pry-byebug', platforms: :ruby

gemspec path: '../'
8 changes: 8 additions & 0 deletions gemfiles/rails_6_1.gemfile
@@ -0,0 +1,8 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "pry-byebug", platforms: :ruby
gem "activemodel", "~> 6.1.0"

gemspec path: "../"
8 changes: 7 additions & 1 deletion lib/dynamoid/adapter.rb
Expand Up @@ -158,8 +158,14 @@ def delete_table(table_name, options = {})
#
# @since 0.2.0
def method_missing(method, *args, &block)
return benchmark(method, *args) { adapter.send(method, *args, &block) } if adapter.respond_to?(method)
# Don't use keywork arguments delegating (with **kw). It works in
# different way in different Ruby versions: <= 2.6, 2.7, 3.0 and in some
# future 3.x versions. Providing that there are no downstream methods
# with keyword arguments in adapter.
#
# https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html

return benchmark(method, *args) { adapter.send(method, *args, &block) } if adapter.respond_to?(method)
super
end

Expand Down
11 changes: 10 additions & 1 deletion lib/dynamoid/adapter_plugin/aws_sdk_v3.rb
Expand Up @@ -12,6 +12,15 @@ module Dynamoid
# @private
module AdapterPlugin
# The AwsSdkV3 adapter provides support for the aws-sdk version 2 for ruby.

# Note: Don't use keyword arguments in public methods as far as method
# calls on adapter are delegated to the plugin.
#
# There are breaking changes in Ruby related to delegating keyword
# arguments so we have decided just to avoid them when use delegation.
#
# https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html

class AwsSdkV3
EQ = 'EQ'
RANGE_MAP = {
Expand Down Expand Up @@ -281,7 +290,7 @@ def create_table(table_name, key = :id, options = {})
false
end

def update_time_to_live(table_name:, attribute:)
def update_time_to_live(table_name, attribute)
request = {
table_name: table_name,
time_to_live_specification: {
Expand Down
7 changes: 7 additions & 0 deletions lib/dynamoid/criteria.rb
Expand Up @@ -15,6 +15,13 @@ module ClassMethods
#
# @since 0.2.0
define_method(meth) do |*args, &blk|
# Don't use keywork arguments delegating (with **kw). It works in
# different way in different Ruby versions: <= 2.6, 2.7, 3.0 and in some
# future 3.x versions. Providing that there are no downstream methods
# with keyword arguments in Chain.
#
# https://eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html

chain = Dynamoid::Criteria::Chain.new(self)
if args
chain.send(meth, *args, &blk)
Expand Down
2 changes: 1 addition & 1 deletion lib/dynamoid/loadable.rb
Expand Up @@ -23,7 +23,7 @@ def reload
options[:range_key] = range_value
end

self.attributes = self.class.find(hash_key, options).attributes
self.attributes = self.class.find(hash_key, **options).attributes
@associations.values.each(&:reset)
self
end
Expand Down
2 changes: 1 addition & 1 deletion lib/dynamoid/persistence.rb
Expand Up @@ -112,7 +112,7 @@ def create_table(options = {})

if created_successfuly && self.options[:expires]
attribute = self.options[:expires][:field]
Dynamoid.adapter.update_time_to_live(table_name: table_name, attribute: attribute)
Dynamoid.adapter.update_time_to_live(table_name, attribute)
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/dynamoid/persistence/update_fields.rb
Expand Up @@ -4,8 +4,8 @@ module Dynamoid
module Persistence
# @private
class UpdateFields
def self.call(*args)
new(*args).call
def self.call(*args, **options)
new(*args, **options).call
end

def initialize(model_class, partition_key:, sort_key:, attributes:, conditions:)
Expand Down
4 changes: 2 additions & 2 deletions lib/dynamoid/persistence/upsert.rb
Expand Up @@ -4,8 +4,8 @@ module Dynamoid
module Persistence
# @private
class Upsert
def self.call(*args)
new(*args).call
def self.call(*args, **options)
new(*args, **options).call
end

def initialize(model_class, partition_key:, sort_key:, attributes:, conditions:)
Expand Down
5 changes: 4 additions & 1 deletion lib/dynamoid/validations.rb
Expand Up @@ -50,7 +50,10 @@ def validates_presence_of(*attr_names)
class PresenceValidator < ActiveModel::EachValidator
# Validate the record for the record and value.
def validate_each(record, attr_name, value)
record.errors.add(attr_name, :blank, options) if not_present?(value)
# Use keyword argument `options` because it was a Hash in Rails < 6.1
# and became a keyword argument in 6.1. This way it works in both
# cases.
record.errors.add(attr_name, :blank, **options) if not_present?(value)
end

private
Expand Down
4 changes: 2 additions & 2 deletions spec/dynamoid/adapter_plugin/aws_sdk_v3_spec.rb
Expand Up @@ -1224,11 +1224,11 @@ def dynamo_request(table_name, scan_hash = {}, select_opts = {})
)
.and_call_original

Dynamoid.adapter.update_time_to_live(table_name: table_name, attribute: :ttl)
Dynamoid.adapter.update_time_to_live(table_name, :ttl)
end

it 'updates a table schema' do
Dynamoid.adapter.update_time_to_live(table_name: table_name, attribute: :ttl)
Dynamoid.adapter.update_time_to_live(table_name, :ttl)

response = Dynamoid.adapter.client.describe_time_to_live(table_name: table_name)
expect(response.time_to_live_description.time_to_live_status).to eq 'ENABLED'
Expand Down
7 changes: 6 additions & 1 deletion spec/dynamoid/persistence_spec.rb
Expand Up @@ -416,8 +416,13 @@ def self.dynamoid_field_type
end

it 'sets up TTL for table' do
# Run the spec when a fix in rspec-mock is released
# - https://github.com/rspec/rspec-mocks/issues/1306
# - https://github.com/rspec/rspec-mocks/pull/1385
skip "There is an issue with Ruby 3.0 and rspec-mocks related to keyword arguments"

expect(Dynamoid.adapter).to receive(:update_time_to_live)
.with(table_name: class_with_expiration.table_name, attribute: :ttl)
.with(class_with_expiration.table_name, :ttl)
.and_call_original

class_with_expiration.create_table
Expand Down

0 comments on commit 4e09761

Please sign in to comment.