Skip to content

Commit

Permalink
Preserve Ruby 2.7 behavior for Ruby keyword args (#11)
Browse files Browse the repository at this point in the history
Applies [`ruby2_keywords`](https://github.com/ruby/ruby2_keywords) to the `Command.call` method, which preserves the Ruby 2.7 behavior for keyword args.

The result of these changes is that Rectify will continue to work with the existing behavior for keyword args once we've upgraded Panacea to Ruby 3. We've had to take this approach because fixing it would have also required us to upgrade Rectify to only work on Ruby `>= 3.0`. This is due to the fact that our particular use of kwargs in the Command pattern are considered a "corner case", preventing us from adopting the new behavior in our Ruby 2.7 code.

See: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/ - search this page for the string "If your code doesn’t have to run on Ruby 2.6 or older"

## So what does all this mean?

In short, we don't have to worry about Rectify anymore. Once this has merged, we've released 0.14.0, and we've updated Panacea to use this new version, our existing use of Rectify Commands will continue to work even after we've upgraded the application to run on Ruby 3.0.

This allows us to almost forget about the old Rectify-powered commands, and begin thinking about what tool or pattern we introduce to replace Rectify.
  • Loading branch information
Jonic authored Aug 15, 2023
1 parent bfce7c3 commit f335995
Show file tree
Hide file tree
Showing 19 changed files with 122 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ jobs:
with:
bundler-cache: true
- name: Run rubocop
run: bin/rubocop
run: bin/rubocop --format fuubar
1 change: 0 additions & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
--color
--format Fuubar
--require spec_helper
1 change: 0 additions & 1 deletion .rubocop
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
--display-style-guide
--format fuubar
--parallel
32 changes: 15 additions & 17 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@ PATH
activemodel (~> 7.0)
activerecord (~> 7.0)
activesupport (~> 7.0)
virtus (~> 1.0)
wisper (~> 1.6)
virtus (~> 2.0)
wisper (~> 2.0)

GEM
remote: https://rubygems.org/
specs:
actionpack (7.0.6)
actionview (= 7.0.6)
activesupport (= 7.0.6)
actionpack (7.0.7)
actionview (= 7.0.7)
activesupport (= 7.0.7)
rack (~> 2.0, >= 2.2.4)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (7.0.6)
activesupport (= 7.0.6)
actionview (7.0.7)
activesupport (= 7.0.7)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activemodel (7.0.6)
activesupport (= 7.0.6)
activerecord (7.0.6)
activemodel (= 7.0.6)
activesupport (= 7.0.6)
activesupport (7.0.6)
activemodel (7.0.7)
activesupport (= 7.0.7)
activerecord (7.0.7)
activemodel (= 7.0.7)
activesupport (= 7.0.7)
activesupport (7.0.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
Expand All @@ -53,7 +53,6 @@ GEM
thread_safe (~> 0.3, >= 0.3.1)
diff-lcs (1.5.0)
docile (1.4.0)
equalizer (0.0.11)
erubi (1.12.0)
ffi (1.15.5)
formatador (1.1.0)
Expand Down Expand Up @@ -187,12 +186,11 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.4.2)
virtus (1.0.5)
virtus (2.0.0)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
wisper (1.6.1)
wisper (2.0.1)
wisper-rspec (1.1.0)

PLATFORMS
Expand Down
12 changes: 12 additions & 0 deletions Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ guard(:rspec, cmd: "bin/rspec") do
# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)

fixtures = [
{ dir: "commands", spec: "command" },
{ dir: "controllers", spec: "controller_helpers" },
{ dir: "forms", spec: "form" },
{ dir: "presenters", spec: "presenter" },
{ dir: "queries", spec: "query" }
]

fixtures.each do |dir:, spec:|
watch(%r{^spec/fixtures/#{dir}/.+\.rb$}) { rspec.spec.call("lib/rectify/#{spec}") }
end
end

guard(:rubocop, all_on_start: false) do
Expand Down
16 changes: 9 additions & 7 deletions lib/rectify/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ def respond_to_missing?(_method_name, _include_private = false)
class Command
include Wisper::Publisher

def self.call(*args, &block)
event_recorder = EventRecorder.new
class << self
ruby2_keywords def call(*args, &block)
event_recorder = EventRecorder.new

command = new(*args)
command.subscribe(event_recorder)
command.evaluate(&block) if block
command.call
command = new(*args)
command.subscribe(event_recorder)
command.evaluate(&block) if block
command.call

event_recorder.events
event_recorder.events
end
end

def evaluate(&block)
Expand Down
4 changes: 2 additions & 2 deletions rectify.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ Gem::Specification.new do |spec|
spec.add_dependency "activemodel", "~> 7.0"
spec.add_dependency "activerecord", "~> 7.0"
spec.add_dependency "activesupport", "~> 7.0"
spec.add_dependency "virtus", "~> 1.0"
spec.add_dependency "wisper", "~> 1.6"
spec.add_dependency "virtus", "~> 2.0"
spec.add_dependency "wisper", "~> 2.0"
end
3 changes: 0 additions & 3 deletions spec/fixtures/command/args_command.rb

This file was deleted.

15 changes: 15 additions & 0 deletions spec/fixtures/commands/args_command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class ArgsCommand < Rectify::Command
def initialize(a, b, c) # rubocop:disable Lint/MissingSuper, Naming/MethodParameterName
@a = a
@b = b
@c = c
end

def call
[a, b, c].join(" ")
end

private

attr_reader :a, :b, :c
end
File renamed without changes.
40 changes: 40 additions & 0 deletions spec/fixtures/commands/named_args_command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class NamedArgsCommand < Rectify::Command
def initialize(first_name, last_name, height:, location:, hobbies:) # rubocop:disable Lint/MissingSuper
@first_name = first_name
@last_name = last_name
@height = height
@location = location
@hobbies = hobbies
end

def call
broadcast(:ok, message)
end

def message
"#{full_name} is from #{location} and is #{height_in_inches} inches tall, and they enjoy #{hobbies_list}."
end

private

attr_reader :first_name, :last_name, :height, :location, :hobbies

def full_name
[first_name, last_name].join(" ")
end

def height_in_inches
height * 0.393
end

def hobbies_list
hobbies_array = [hobbies].flatten

if hobbies_array.length > 1
last_hobby = "and #{hobbies_array.pop}"
hobbies_array.push(last_hobby)
end

hobbies_array.join(", ")
end
end
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion spec/fixtures/queries/users_over_using_sql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def model
end

def sql
<<-SQL.strip_heredoc
<<~SQL.strip_heredoc
SELECT *
FROM users
WHERE age > :age
Expand Down
12 changes: 12 additions & 0 deletions spec/lib/rectify/command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
expect(ArgsCommand).to have_received(:new).with(:a, :b, :c) { instance }
expect(instance).to have_received(:call)
end

it "supports named arguments" do
NamedArgsCommand.call(
"Andy",
"Pike",
height: 185,
location: "UK",
hobbies: ["running", "climbing", "fishing with grenades"]
) do
on(:ok) { |message| expect(message).to be_a(String) }
end
end
end
end

Expand Down
16 changes: 15 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
module WarningHandlers
module Ruby
class Warning < StandardError; end

def warn(message)
logger = Logger.new("tmp/log/warnings.log")
logger.warn(message)
end
end
end

Warning.singleton_class.prepend(WarningHandlers::Ruby)
Warning[:deprecated] = true

unless ENV["DISABLE_COVERAGE"]
require "simplecov"
SimpleCov.start do
Expand Down Expand Up @@ -34,7 +48,7 @@
config.disable_monkey_patching!

config.backtrace_exclusion_patterns << /gems/
config.default_formatter = "doc" if config.files_to_run.one?
config.default_formatter = config.files_to_run.one? ? "doc" : "Fuubar"
config.example_status_persistence_file_path = "spec/examples.txt"
config.filter_run_when_matching :focus
config.order = :random
Expand Down

0 comments on commit f335995

Please sign in to comment.