diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..8387e94 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,61 @@ +# The behavior of RuboCop can be controlled via the .rubocop.yml +# configuration file. It makes it possible to enable/disable +# certain cops (checks) and to alter their behavior if they accept +# any parameters. The file can be placed either in your home +# directory or in some project directory. +# +# RuboCop will start looking for the configuration file in the directory +# where the inspected file is and continue its way up to the root directory. +# +# See https://docs.rubocop.org/rubocop/configuration + +require: rubocop-performance + +AllCops: + NewCops: enable + SuggestExtensions: false + Exclude: + - 'bin/*' + +Style/Lambda: + Enabled: false + +Style/Alias: + EnforcedStyle: prefer_alias_method + +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/HashSyntax: + Exclude: + - Rakefile + +Metrics/BlockLength: + Exclude: + - 'spec/**/*.rb' + - 'lib/pathway/rspec/matchers/*.rb' + +Layout/EmptyLinesAroundBlockBody: + Exclude: + - 'spec/**/*.rb' + +Layout/MultilineMethodCallIndentation: + EnforcedStyle: indented_relative_to_receiver + +Naming/MethodParameterName: + MinNameLength: 2 + +Style/ParallelAssignment: + Enabled: False + +Style/CaseEquality: + Enabled: False + +Style/Documentation: + Enabled: false + +Lint/MissingSuper: + AllowedParentClasses: [Result] + +Style/AccessModifierDeclarations: + AllowModifiersOnAliasMethod: true diff --git a/Rakefile b/Rakefile index 4741b9d..ee617bb 100644 --- a/Rakefile +++ b/Rakefile @@ -3,10 +3,6 @@ require "bundler/gem_tasks" require "rspec/core/rake_task" -RSpec::Core::RakeTask.new(:spec) do |t| - unless RUBY_VERSION =~ /^2\.7|^3\./ - t.exclude_pattern = 'spec/operation_call_pattern_matching_spec.rb,spec/state_pattern_matching_spec.rb' - end -end +RSpec::Core::RakeTask.new(:spec) task :default => :spec diff --git a/bin/racc b/bin/racc new file mode 100755 index 0000000..8190015 --- /dev/null +++ b/bin/racc @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'racc' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("racc", "racc") diff --git a/bin/rubocop b/bin/rubocop new file mode 100755 index 0000000..369a05b --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/bin/ruby-parse b/bin/ruby-parse new file mode 100755 index 0000000..d8ebc68 --- /dev/null +++ b/bin/ruby-parse @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'ruby-parse' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parser", "ruby-parse") diff --git a/bin/ruby-rewrite b/bin/ruby-rewrite new file mode 100755 index 0000000..b4574ab --- /dev/null +++ b/bin/ruby-rewrite @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'ruby-rewrite' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parser", "ruby-rewrite") diff --git a/lib/pathway.rb b/lib/pathway.rb index 7b4252c..561669a 100644 --- a/lib/pathway.rb +++ b/lib/pathway.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'forwardable' -require 'dry/inflector' -require 'contextualizer' -require 'pathway/version' -require 'pathway/result' +require "forwardable" +require "dry/inflector" +require "contextualizer" +require "pathway/version" +require "pathway/result" module Pathway Inflector = Dry::Inflector.new @@ -56,7 +56,7 @@ def default_message_for(type) class State extend Forwardable - delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash + delegate %i[[] []= fetch store include? values_at deconstruct_keys] => :@hash def initialize(operation, values = {}) @hash = operation.context.merge(values) @@ -72,16 +72,16 @@ def result = @hash[@result_key] def to_hash = @hash def use(&bl) - raise ArgumentError, 'a block must be provided' if !block_given? + raise ArgumentError, "a block must be provided" if !block_given? if bl.parameters in [*, [:rest|:keyrest,], *] - raise ArgumentError, 'rest arguments are not supported' + raise ArgumentError, "rest arguments are not supported" end keys = bl.parameters.select { _1 in :key|:keyreq, }.map(&:last) names = bl.parameters.select { _1 in :req|:opt, }.map(&:last) if keys.any? && names.any? - raise ArgumentError, 'cannot mix positional and keyword arguments' + raise ArgumentError, "cannot mix positional and keyword arguments" elsif keys.any? bl.call(**to_hash.slice(*keys)) else @@ -120,12 +120,12 @@ def inherited(subclass) module InstanceMethods extend Forwardable - delegate :result_key => 'self.class' + delegate :result_key => "self.class" delegate %i[result success failure] => Result alias_method :wrap, :result - def call(*) = raise 'must implement at subclass' + def call(*) = raise "must implement at subclass" def error(type, message: nil, details: nil) failure(Error.new(type:, message:, details:)) @@ -156,27 +156,17 @@ def run(&steps) end # Execute step and preserve the former state - def step(callable,...) - #:nocov: - if block_given? - warn "[DEPRECATION] Passing a block to the step method using `DSLMethods#step` is deprecated" - end - #:nocov: - bl = _callable(callable) - @result = @result.tee { |state| bl.call(state,...) } + def step(callable,*,**, &) + bl = _callable(callable, &) + @result = @result.tee { |state| bl.call(state,*,**) } end # Execute step and modify the former state setting the key - def set(callable, *args, to: @operation.result_key, **kwargs, &bl) - #:nocov: - if block_given? - warn "[DEPRECATION] Passing a block to the step method using `DSLMethods#set` is deprecated" - end - #:nocov: - bl = _callable(callable) + def set(callable, *args, to: @operation.result_key, **kwargs, &) + bl = _callable(callable, &) @result = @result.then do |state| - wrap(bl.call(state, *args, **kwargs, &bl)) + wrap(bl.call(state, *args, **kwargs)) .then { |value| state.update(to => value) } end end @@ -214,14 +204,21 @@ def if_false(cond, &steps) def wrap(obj) = Result.result(obj) - def _callable(callable) - case callable - when Proc # unless (callable.binding rescue nil)&.receiver == @operation - ->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) } - when Symbol - ->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) } + def _callable(callable, &bl) + if block_given? + raise ArgumentError, 'You must either pass a block or a callable but not both' if !callable.is_a?(Symbol) + warn "The operation already responds to a message of the same name" if @operation.responds_to?(callable) + + ->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &bl) } else - callable + case callable + when Proc + ->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) } + when Symbol + ->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) } + else + callable + end end end end diff --git a/lib/pathway/plugins/auto_deconstruct_state.rb b/lib/pathway/plugins/auto_deconstruct_state.rb index 1578616..ffe16c3 100644 --- a/lib/pathway/plugins/auto_deconstruct_state.rb +++ b/lib/pathway/plugins/auto_deconstruct_state.rb @@ -8,10 +8,10 @@ module DSLMethods def _callable(callable) if callable.is_a?(Symbol) && @operation.respond_to?(callable, true) && - @operation.method(callable).arity != 0 && - @operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block,*] } + @operation.method(callable).arity != 0 && + @operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block, *] } - -> state { @operation.send(callable, **state) } + ->(state) { @operation.send(callable, **state) } else super end diff --git a/lib/pathway/plugins/dry_validation.rb b/lib/pathway/plugins/dry_validation.rb index 8e73346..0145bc9 100644 --- a/lib/pathway/plugins/dry_validation.rb +++ b/lib/pathway/plugins/dry_validation.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'dry/validation' +require "dry/validation" module Pathway module Plugins @@ -16,7 +16,7 @@ def contract(base = nil, &) elsif base self.contract_class = base else - raise ArgumentError, 'Either a contract class or a block must be provided' + raise ArgumentError, "Either a contract class or a block must be provided" end end @@ -50,7 +50,7 @@ def _base_contract module InstanceMethods extend Forwardable - delegate %i[build_contract contract_options auto_wire] => 'self.class' + delegate %i[build_contract contract_options auto_wire] => "self.class" alias_method :contract, :build_contract def validate(state, with: nil) diff --git a/lib/pathway/plugins/responder.rb b/lib/pathway/plugins/responder.rb index ded29d3..f39be5d 100644 --- a/lib/pathway/plugins/responder.rb +++ b/lib/pathway/plugins/responder.rb @@ -34,7 +34,7 @@ def failure(type = nil, &bl) def respond if @result.success? @context.instance_exec(@result.value, &@ok) - elsif Error === @result.error && fail_block = @fails[@result.error.type] + elsif Error === @result.error && (fail_block = @fails[@result.error.type]) @context.instance_exec(@result.error, &fail_block) else @context.instance_exec(@result.error, &@fail_default) diff --git a/lib/pathway/plugins/sequel_models.rb b/lib/pathway/plugins/sequel_models.rb index b0979cd..a391fc5 100644 --- a/lib/pathway/plugins/sequel_models.rb +++ b/lib/pathway/plugins/sequel_models.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'sequel/model' +require "sequel/model" module Pathway module Plugins @@ -33,8 +33,8 @@ def after_rollback(step_name = nil, if: nil, unless: nil, &steps) def _opts_if_unless(bg) = %i[if unless].map { bg.local_variable_get(_1) } def _with_db_steps(steps, step_name=nil, if_cond=nil, unless_cond=nil, &db_logic) - raise ArgumentError, 'options :if and :unless are mutually exclusive' if if_cond && unless_cond - raise ArgumentError, 'must provide either a step or a block but not both' if !!step_name == !!steps + raise ArgumentError, "options :if and :unless are mutually exclusive" if if_cond && unless_cond + raise ArgumentError, "must provide either a step or a block but not both" if !!step_name == !!steps steps ||= proc { step step_name } if if_cond @@ -69,7 +69,7 @@ def inherited(subclass) module InstanceMethods extend Forwardable - delegate %i[model_class search_field model_not_found] => 'self.class' + delegate %i[model_class search_field model_not_found] => "self.class" delegate :db => :model_class def fetch_model(state, from: model_class, search_by: search_field, using: search_by, to: result_key, overwrite: false, error_message: nil) @@ -77,7 +77,7 @@ def fetch_model(state, from: model_class, search_by: search_field, using: search model_not_found elsif from.respond_to?(:name) || from.respond_to?(:model) from_name = (from.respond_to?(:name) ? from : from.model).name - Inflector.humanize(Inflector.underscore(Inflector.demodulize(from_name))) + ' not found' + Inflector.humanize(Inflector.underscore(Inflector.demodulize(from_name))) + " not found" end if state[to].nil? || overwrite diff --git a/lib/pathway/result.rb b/lib/pathway/result.rb index 634ddb7..416fb51 100644 --- a/lib/pathway/result.rb +++ b/lib/pathway/result.rb @@ -9,8 +9,8 @@ class Success < Result def initialize(value) = @value = value def success? = true - def then(bl=nil) - result(block_given? ? yield(value): bl.call(value)) + def then(bl = nil) + result(block_given? ? yield(value) : bl.call(value)) end def tee(...) @@ -18,20 +18,16 @@ def tee(...) follow.failure? ? follow : self end - private - - alias_method :value_for_deconstruct, :value + private alias_method :value_for_deconstruct, :value end class Failure < Result def initialize(error) = @error = error def success? = false - def then(_=nil) = self - def tee(_=nil) = self - - private + def then(_ = nil) = self + def tee(_ = nil) = self - alias_method :value_for_deconstruct, :error + private alias_method :value_for_deconstruct, :error end module Mixin @@ -57,6 +53,6 @@ def deconstruct_keys(keys) end end - delegate :result => 'self.class' + delegate result: "self.class" end end diff --git a/lib/pathway/rspec.rb b/lib/pathway/rspec.rb index 9223901..6161369 100644 --- a/lib/pathway/rspec.rb +++ b/lib/pathway/rspec.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers' +require "pathway/rspec/matchers" diff --git a/lib/pathway/rspec/matchers.rb b/lib/pathway/rspec/matchers.rb index 73d15b4..c7efc21 100644 --- a/lib/pathway/rspec/matchers.rb +++ b/lib/pathway/rspec/matchers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/succeed_on' -require 'pathway/rspec/matchers/fail_on' -require 'pathway/rspec/matchers/accept_optional_fields' -require 'pathway/rspec/matchers/require_fields' +require "pathway/rspec/matchers/succeed_on" +require "pathway/rspec/matchers/fail_on" +require "pathway/rspec/matchers/accept_optional_fields" +require "pathway/rspec/matchers/require_fields" diff --git a/lib/pathway/rspec/matchers/accept_optional_fields.rb b/lib/pathway/rspec/matchers/accept_optional_fields.rb index 200b176..b9e85b6 100644 --- a/lib/pathway/rspec/matchers/accept_optional_fields.rb +++ b/lib/pathway/rspec/matchers/accept_optional_fields.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/form_schema_helpers' +require "pathway/rspec/matchers/form_schema_helpers" RSpec::Matchers.define :accept_optional_fields do |*fields| match do |form| @@ -13,7 +13,7 @@ end match_when_negated do |form| - raise NotImplementedError, 'expect().not_to accept_optional_fields.not_allowing_null_values is not supported.' if @allowing_null_values || @not_allowing_null_values + raise NotImplementedError, "expect().not_to accept_optional_fields.not_allowing_null_values is not supported." if @allowing_null_values || @not_allowing_null_values @form, @fields = form, fields @@ -21,23 +21,23 @@ end description do - null_value_allowed = @allowing_null_values ? ' allowing null values' : '' - null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : '' + null_value_allowed = @allowing_null_values ? " allowing null values" : "" + null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : "" "accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed}" end failure_message do - null_value_allowed = @allowing_null_values ? ' allowing null values' : '' - null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : '' + null_value_allowed = @allowing_null_values ? " allowing null values" : "" + null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : "" "Expected to accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed} but " + as_sentence([not_optional_list, not_defined_list, accepting_null_list, not_accepting_null_list].compact, - connector: '; ', last_connector: '; and ') + connector: "; ", last_connector: "; and ") end failure_message_when_negated do "Did not expect to accept #{field_list} as optional #{pluralize_fields} but " + - [optional_list, not_defined_list].compact.join('; and ') + [optional_list, not_defined_list].compact.join("; and ") end include Pathway::Rspec::FormSchemaHelpers @@ -51,13 +51,13 @@ def not_optional_list end chain :allowing_null_values do - fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @not_allowing_null_values + raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @not_allowing_null_values @allowing_null_values = true end chain :not_allowing_null_values do - fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @allowing_null_values + raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @allowing_null_values @not_allowing_null_values = true end diff --git a/lib/pathway/rspec/matchers/fail_on.rb b/lib/pathway/rspec/matchers/fail_on.rb index c36344a..4e545ab 100644 --- a/lib/pathway/rspec/matchers/fail_on.rb +++ b/lib/pathway/rspec/matchers/fail_on.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/list_helpers' +require "pathway/rspec/matchers/list_helpers" RSpec::Matchers.define :fail_on do |input| match do |operation| @@ -10,9 +10,10 @@ end match_when_negated do |operation| - raise NotImplementedError, '`expect().not_to fail_on(input).with_type()` is not supported.' if @type - raise NotImplementedError, '`expect().not_to fail_on(input).with_message()` is not supported.' if @message - raise NotImplementedError, '`expect().not_to fail_on(input).with_details()` is not supported.' if @details + raise NotImplementedError, "`expect().not_to fail_on(input).with_type()` is not supported." if @type + raise NotImplementedError, "`expect().not_to fail_on(input).with_message()` is not supported." if @message + raise NotImplementedError, "`expect().not_to fail_on(input).with_details()` is not supported." if @details + @operation, @input = operation, input !failure? @@ -40,20 +41,20 @@ alias_method :and_details, :details description do - 'fail' + (@type ? " with :#@type error" : '') + "fail" + (@type ? " with :#@type error" : "") end failure_message do if !failure? "Expected operation to fail but it didn't" else - 'Expected failed operation to ' + - as_sentence(failure_descriptions, connector: '; ', last_connector: '; and ') + "Expected failed operation to " + + as_sentence(failure_descriptions, connector: "; ", last_connector: "; and ") end end failure_message_when_negated do - 'Did not expected operation to fail but it did' + "Did not expected operation to fail but it did" end def failure? diff --git a/lib/pathway/rspec/matchers/field_list_helpers.rb b/lib/pathway/rspec/matchers/field_list_helpers.rb index 0b3cb43..12d41eb 100644 --- a/lib/pathway/rspec/matchers/field_list_helpers.rb +++ b/lib/pathway/rspec/matchers/field_list_helpers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/list_helpers' +require "pathway/rspec/matchers/list_helpers" module Pathway module Rspec @@ -12,11 +12,11 @@ def field_list end def were_was(list) - list.size > 1 ? 'were' : 'was' + list.size > 1 ? "were" : "was" end def pluralize_fields - @fields.size > 1 ? 'fields' : 'field' + @fields.size > 1 ? "fields" : "field" end end end diff --git a/lib/pathway/rspec/matchers/form_schema_helpers.rb b/lib/pathway/rspec/matchers/form_schema_helpers.rb index 9cbd4d8..e9e9d14 100644 --- a/lib/pathway/rspec/matchers/form_schema_helpers.rb +++ b/lib/pathway/rspec/matchers/form_schema_helpers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/field_list_helpers' +require "pathway/rspec/matchers/field_list_helpers" module Pathway module Rspec diff --git a/lib/pathway/rspec/matchers/list_helpers.rb b/lib/pathway/rspec/matchers/list_helpers.rb index 9e647eb..fe13560 100644 --- a/lib/pathway/rspec/matchers/list_helpers.rb +++ b/lib/pathway/rspec/matchers/list_helpers.rb @@ -7,10 +7,10 @@ def as_list(items, **kwargs) as_sentence(items.map(&:inspect), **kwargs) end - def as_sentence(items, connector: ', ', last_connector: ' and ') + def as_sentence(items, connector: ", ", last_connector: " and ") *rest, last = items - result = String.new + result = +"" result << rest.join(connector) << last_connector if rest.any? result << last end diff --git a/lib/pathway/rspec/matchers/require_fields.rb b/lib/pathway/rspec/matchers/require_fields.rb index 82ac23b..284a145 100644 --- a/lib/pathway/rspec/matchers/require_fields.rb +++ b/lib/pathway/rspec/matchers/require_fields.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'pathway/rspec/matchers/form_schema_helpers' +require "pathway/rspec/matchers/form_schema_helpers" RSpec::Matchers.define :require_fields do |*fields| match do |form| @@ -13,7 +13,7 @@ end match_when_negated do |form| - raise NotImplementedError, 'expect().not_to require_fields.not_allowing_null_values is not supported.' if @allowing_null_values || @not_allowing_null_values + raise NotImplementedError, "expect().not_to require_fields.not_allowing_null_values is not supported." if @allowing_null_values || @not_allowing_null_values @form, @fields = form, fields @@ -21,23 +21,23 @@ end description do - null_value_allowed = @allowing_null_values ? ' allowing null values' : '' - null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : '' + null_value_allowed = @allowing_null_values ? " allowing null values" : "" + null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : "" "require #{field_list} as #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed}" end failure_message do - null_value_allowed = @allowing_null_values ? ' allowing null values' : '' - null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : '' + null_value_allowed = @allowing_null_values ? " allowing null values" : "" + null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : "" "Expected to require #{field_list} as #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed} but " + as_sentence([not_required_list, not_defined_list, accepting_null_list, not_accepting_null_list].compact, - connector: '; ', last_connector: '; and ') + connector: "; ", last_connector: "; and ") end failure_message_when_negated do "Did not expect to require #{field_list} as #{pluralize_fields} but " + - [required_list, not_defined_list].compact.join('; and ') + [required_list, not_defined_list].compact.join("; and ") end include Pathway::Rspec::FormSchemaHelpers @@ -51,13 +51,13 @@ def not_required_list end chain :allowing_null_values do - fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @not_allowing_null_values + raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @not_allowing_null_values @allowing_null_values = true end chain :not_allowing_null_values do - fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @allowing_null_values + raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @allowing_null_values @not_allowing_null_values = true end diff --git a/lib/pathway/rspec/matchers/succeed_on.rb b/lib/pathway/rspec/matchers/succeed_on.rb index 2a5c39c..e2dee8e 100644 --- a/lib/pathway/rspec/matchers/succeed_on.rb +++ b/lib/pathway/rspec/matchers/succeed_on.rb @@ -8,7 +8,8 @@ end match_when_negated do |operation| - raise NotImplementedError, '`expect().not_to succeed_on(input).returning()` is not supported.' if @value + raise NotImplementedError, "`expect().not_to succeed_on(input).returning()` is not supported." if @value + @operation, @input = operation, input !success? @@ -31,7 +32,7 @@ end failure_message_when_negated do - 'Did not to expected operation to be successful but it was' + "Did not to expected operation to be successful but it was" end def success? diff --git a/pathway.gemspec b/pathway.gemspec index c2c3f94..200ae4f 100644 --- a/pathway.gemspec +++ b/pathway.gemspec @@ -37,7 +37,9 @@ Gem::Specification.new do |spec| spec.add_development_dependency "sequel", "~> 5.0" spec.add_development_dependency "rake", "~> 13.0" spec.add_development_dependency "rspec", "~> 3.11" - spec.add_development_dependency "simplecov-lcov", '~> 0.8.0' + spec.add_development_dependency "simplecov-lcov", "~> 0.8.0" + spec.add_development_dependency "rubocop", "~> 1.71.0" + spec.add_development_dependency "rubocop-performance" spec.add_development_dependency "simplecov" spec.add_development_dependency "pry" spec.add_development_dependency "reline" diff --git a/spec/operation_call_pattern_matching_spec.rb b/spec/operation_call_pattern_matching_spec.rb index f11ba08..163d85e 100644 --- a/spec/operation_call_pattern_matching_spec.rb +++ b/spec/operation_call_pattern_matching_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway class Result module Mixin - describe 'Operation call with pattern matching' do + describe "Operation call with pattern matching" do class RespOperation < Operation context :with @@ -88,7 +88,7 @@ def call(_) context "and the pattern is Failure with :type and :details specified" do let(:passed_result) do - Result.failure(Error.new(type: :validation, details: ['name missing', 'email missing'])) + Result.failure(Error.new(type: :validation, details: ["name missing", "email missing"])) end it "returns the result according to :type" do @@ -138,7 +138,7 @@ def call(_) context "and the pattern is Failure with :type and :details specified" do let(:passed_result) do - Result.failure(Error.new(type: :validation, details: ['name missing', 'email missing'])) + Result.failure(Error.new(type: :validation, details: ["name missing", "email missing"])) end it "returns the result according to :type" do diff --git a/spec/plugins/auto_deconstruct_state_spec.rb b/spec/plugins/auto_deconstruct_state_spec.rb index bc870ac..6b9b2de 100644 --- a/spec/plugins/auto_deconstruct_state_spec.rb +++ b/spec/plugins/auto_deconstruct_state_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins - describe 'AutoDeconstructState' do + describe "AutoDeconstructState" do class KwargsOperation < Operation plugin :auto_deconstruct_state @@ -34,8 +34,8 @@ def create_model(name:, email:, **) UserModel.new(name, email) end - def notify(s) - s.u do |value:| + def notify(st) + st.u do |value:| @notifier.call(value) end end @@ -47,8 +47,8 @@ def notify(s) subject(:operation) { KwargsOperation.new(ctx) } let(:ctx) { { validator: validator, name_repo: name_repo, email_repo: email_repo, notifier: notifier } } - let(:name) { 'Paul Smith' } - let(:email) { 'psmith@email.com' } + let(:name) { "Paul Smith" } + let(:email) { "psmith@email.com" } let(:input) { { id: 99 } } let(:validator) do @@ -81,7 +81,7 @@ def notify(s) end end - it 'destructure arguments on steps with only kwargs', :aggregate_failures do + it "destructure arguments on steps with only kwargs", :aggregate_failures do operation.call(input) end end diff --git a/spec/plugins/base_spec.rb b/spec/plugins/base_spec.rb index d139e0b..6e35abc 100644 --- a/spec/plugins/base_spec.rb +++ b/spec/plugins/base_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins @@ -84,7 +84,7 @@ def notify(state) allow(notifier).to receive(:call) end - let(:valid_input) { { foo: 'FOO' } } + let(:valid_input) { { foo: "FOO" } } describe ".process" do it "defines a 'call' method wich saves operation argument into the :input key" do diff --git a/spec/plugins/dry_validation_spec.rb b/spec/plugins/dry_validation_spec.rb index 43c4fd5..cb5bcb7 100644 --- a/spec/plugins/dry_validation_spec.rb +++ b/spec/plugins/dry_validation_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins - describe 'DryValidation' do + describe "DryValidation" do class SimpleOperation < Operation plugin :dry_validation @@ -54,7 +54,7 @@ class OperationWithOpt < Operation end rule(:qux) do - key.failure('not equal to :foo') unless value == foo + key.failure("not equal to :foo") unless value == foo end end @@ -76,7 +76,7 @@ class OperationWithAutoWire < Operation end rule(:qux) do - key.failure('not equal to :foo') unless value == baz + key.failure("not equal to :foo") unless value == baz end end @@ -178,13 +178,13 @@ class OperationWithAutoWire < Operation context "when called with no block nor contract" do subject(:opr_class) { Class.new(Operation) { plugin :dry_validation } } - it 'raises an error' do + it "raises an error" do expect { opr_class.contract } - .to raise_error(ArgumentError, 'Either a contract class or a block must be provided') + .to raise_error(ArgumentError, "Either a contract class or a block must be provided") end end - context 'when the operation is inherited' do + context "when the operation is inherited" do let(:opr_class) { OperationWithAutoWire } subject(:opr_subclass) { Class.new(OperationWithAutoWire) } @@ -219,24 +219,24 @@ class OperationWithAutoWire < Operation context "when calling with invalid params" do let(:params) { { email: "psmith@email.com" } } it "returns a failed result", :aggregate_failures do - expect(operation).to fail_on(params).with_details(name: ['is missing']) + expect(operation).to fail_on(params).with_details(name: ["is missing"]) end end context "when contract requires options for validation" do - subject(:operation) { OperationWithOpt.new(quz: 'XXXXX') } + subject(:operation) { OperationWithOpt.new(quz: "XXXXX") } it "sets then passing a hash through the :with argument" do - expect(operation.call(qux: 'XXXXX')).to be_a_success - expect(operation.call(qux: 'OTHER')).to be_a_failure + expect(operation.call(qux: "XXXXX")).to be_a_success + expect(operation.call(qux: "OTHER")).to be_a_failure end context "and is using auto_wire: true" do - subject(:operation) { OperationWithAutoWire.new(baz: 'XXXXX') } + subject(:operation) { OperationWithAutoWire.new(baz: "XXXXX") } it "sets the options directly from the context using the keys with the same name" do - expect(operation.call(qux: 'XXXXX')).to be_a_success - expect(operation.call(qux: 'OTHER')).to be_a_failure + expect(operation.call(qux: "XXXXX")).to be_a_success + expect(operation.call(qux: "OTHER")).to be_a_failure end end end diff --git a/spec/plugins/responder_spec.rb b/spec/plugins/responder_spec.rb index a9c32cb..dcbd321 100644 --- a/spec/plugins/responder_spec.rb +++ b/spec/plugins/responder_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins - describe 'Responder' do + describe "Responder" do class RespOperation < Operation plugin :responder @@ -16,7 +16,7 @@ def call(_) end let(:input) { {} } - let(:context) { { with: passed_result} } + let(:context) { { with: passed_result } } describe ".call" do context "when no block is given" do @@ -34,7 +34,7 @@ def call(_) let(:result) do RespOperation.call(context, input) do success { |value| "Returning: " + value } - failure { |error| error} + failure { |error| error } end end @@ -75,7 +75,7 @@ def call(_) context "and the result is an error of a specified type" do let(:passed_result) do - Result.failure(Error.new(type: :validation, details: ['name missing', 'email missing'])) + Result.failure(Error.new(type: :validation, details: ["name missing", "email missing"])) end it "executes the right failure type block" do diff --git a/spec/plugins/sequel_models_spec.rb b/spec/plugins/sequel_models_spec.rb index c3f73d1..cd987b9 100644 --- a/spec/plugins/sequel_models_spec.rb +++ b/spec/plugins/sequel_models_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins - describe 'SequelModels' do + describe "SequelModels" do DB = Sequel.mock MyModel = Class.new(Sequel::Model(DB[:foo])) { set_primary_key :pk } @@ -58,18 +58,18 @@ def chain_operation(state) end end - describe 'DSL' do - let(:params) { { email: 'asd@fgh.net' } } + describe "DSL" do + let(:params) { { email: "asd@fgh.net" } } let(:model) { double } let(:mailer) { double.tap { |d| allow(d).to receive(:send_emails) } } - describe '#transaction' do - context 'when providing a block' do + describe "#transaction" do + context "when providing a block" do let(:operation) { MailerOperation.new(mailer: mailer) } before { allow(DB).to receive(:transaction).and_call_original } - it 'returns the result state provided by the inner transaction when successful' do + it "returns the result state provided by the inner transaction when successful" do allow(MyModel).to receive(:first).with(params).and_return(model) expect(operation).to succeed_on(params).returning(model: model) @@ -81,7 +81,7 @@ def chain_operation(state) expect(operation).to fail_on(params).with_type(:not_found) end - context 'a conditional,' do + context "a conditional," do class IfConditionalOperation < PkOperation context :should_run @@ -98,10 +98,10 @@ def should_run?(state)= state[:should_run] let(:operation) { IfConditionalOperation.new(should_run: should_run) } let(:params) { { pk: 77 } } - context 'when the condition is true' do + context "when the condition is true" do let(:should_run) { true } - it 'executes the transaction' do + it "executes the transaction" do expect(DB).to receive(:transaction).once.and_call_original expect(MyModel).to receive(:first).with(params).and_return(model) @@ -109,10 +109,10 @@ def should_run?(state)= state[:should_run] end end - context 'when the condition is false' do + context "when the condition is false" do let(:should_run) { false } - it 'skips the transaction' do + it "skips the transaction" do expect(MyModel).to_not receive(:first) expect(DB).to_not receive(:transaction) @@ -122,7 +122,7 @@ def should_run?(state)= state[:should_run] end end - context 'when providing a step' do + context "when providing a step" do class FetchStepOperation < MyOperation process do transaction :fetch_model @@ -132,7 +132,7 @@ class FetchStepOperation < MyOperation let(:operation) { FetchStepOperation.new(mailer: mailer) } before { allow(DB).to receive(:transaction).and_call_original } - it 'returns the result state provided by the inner transaction when successful' do + it "returns the result state provided by the inner transaction when successful" do allow(MyModel).to receive(:first).with(params).and_return(model) expect(operation).to succeed_on(params).returning(model) @@ -144,7 +144,7 @@ class FetchStepOperation < MyOperation expect(operation).to fail_on(params).with_type(:not_found) end - context 'and conditional' do + context "and conditional" do class UnlessConditionalOperation < PkOperation context :should_skip @@ -163,10 +163,10 @@ def should_skip?(state)= state[:should_skip] let(:operation) { UnlessConditionalOperation.new(should_skip: should_skip) } let(:params) { { pk: 99 } } - context 'if the condition is true' do + context "if the condition is true" do let(:should_skip) { false } - it 'executes the transaction' do + it "executes the transaction" do expect(DB).to receive(:transaction).once.and_call_original expect(MyModel).to receive(:create).with(params).and_return(model) @@ -174,10 +174,10 @@ def should_skip?(state)= state[:should_skip] end end - context 'if the condition is false' do + context "if the condition is false" do let(:should_skip) { true } - it 'skips the transaction' do + it "skips the transaction" do expect(DB).to_not receive(:transaction) expect(MyModel).to_not receive(:create) @@ -187,7 +187,7 @@ def should_skip?(state)= state[:should_skip] end end - context 'when both an :if and :unless conditional' do + context "when both an :if and :unless conditional" do class InvalidUseOfCondOperation < MyOperation process do transaction :perform_db_action, if: :is_good?, unless: :is_bad? @@ -196,13 +196,13 @@ class InvalidUseOfCondOperation < MyOperation let(:operation) { InvalidUseOfCondOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error. - with_message('options :if and :unless are mutually exclusive') + with_message("options :if and :unless are mutually exclusive") end end - context 'when providing a block and a step' do + context "when providing a block and a step" do class AmbivalentTransactOperation < MyOperation process do transaction :perform_db_action do @@ -213,13 +213,13 @@ class AmbivalentTransactOperation < MyOperation let(:operation) { AmbivalentTransactOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('must provide either a step or a block but not both') + .with_message("must provide either a step or a block but not both") end end - context 'when not providing a block nor a step' do + context "when not providing a block nor a step" do class EmptyTransacOperation < MyOperation process do transaction @@ -228,18 +228,18 @@ class EmptyTransacOperation < MyOperation let(:operation) { EmptyTransacOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error. - with_message('must provide either a step or a block but not both') + with_message("must provide either a step or a block but not both") end end end - describe '#after_commit' do - context 'when providing a block' do + describe "#after_commit" do + context "when providing a block" do let(:operation) { MailerOperation.new(mailer: mailer) } - it 'calls after_commit block when transaction is successful' do + it "calls after_commit block when transaction is successful" do expect(DB).to receive(:transaction).and_call_original allow(MyModel).to receive(:first).with(params).and_return(model) expect(DB).to receive(:after_commit).and_call_original @@ -248,7 +248,7 @@ class EmptyTransacOperation < MyOperation expect(operation).to succeed_on(params) end - it 'does not call after_commit block when transaction fails' do + it "does not call after_commit block when transaction fails" do expect(DB).to receive(:transaction).and_call_original allow(MyModel).to receive(:first).with(params).and_return(nil) expect(DB).to_not receive(:after_commit).and_call_original @@ -257,10 +257,10 @@ class EmptyTransacOperation < MyOperation expect(operation).to fail_on(params) end - context 'and the execution state is changed bellow the after_commit callback' do + context "and the execution state is changed bellow the after_commit callback" do let(:operation) { ChainedOperation.new(mailer: mailer) } - it 'ignores any state changes that took place following the after_commit block' do + it "ignores any state changes that took place following the after_commit block" do allow(MyModel).to receive(:first).with(params).and_return(model) expect(mailer).to receive(:send_emails).with(model) @@ -269,7 +269,7 @@ class EmptyTransacOperation < MyOperation end end - context 'when providing a step' do + context "when providing a step" do class SendEmailStepOperation < MyOperation process do transaction do @@ -286,7 +286,7 @@ def send_emails(state) let(:operation) { SendEmailStepOperation.new(mailer: mailer) } before { expect(DB).to receive(:transaction).and_call_original } - it 'calls after_commit block when transaction is successful' do + it "calls after_commit block when transaction is successful" do allow(MyModel).to receive(:first).with(params).and_return(model) expect(DB).to receive(:after_commit).and_call_original expect(mailer).to receive(:send_emails).with(model) @@ -294,7 +294,7 @@ def send_emails(state) expect(operation).to succeed_on(params) end - it 'does not call after_commit block when transaction fails' do + it "does not call after_commit block when transaction fails" do allow(MyModel).to receive(:first).with(params).and_return(nil) expect(DB).to_not receive(:after_commit).and_call_original expect(mailer).to_not receive(:send_emails) @@ -303,8 +303,8 @@ def send_emails(state) end end - context 'with conditional execution' do - context 'using :if with and a block' do + context "with conditional execution" do + context "using :if with and a block" do class IfConditionalAfterCommitOperation < MyOperation context :should_run @@ -326,14 +326,14 @@ def should_run?(state) = state[:should_run] end let(:operation) { IfConditionalAfterCommitOperation.new(mailer: mailer, should_run: should_run) } - let(:params) { { email: 'asd@fgh.net' } } + let(:params) { { email: "asd@fgh.net" } } before { allow(MyModel).to receive(:first).with(params).and_return(model) } - context 'when the condition is true' do + context "when the condition is true" do let(:should_run) { true } - it 'executes the after_commit block' do + it "executes the after_commit block" do expect(DB).to receive(:after_commit).and_call_original expect(mailer).to receive(:send_emails).with(model) @@ -341,10 +341,10 @@ def should_run?(state) = state[:should_run] end end - context 'when the condition is false' do + context "when the condition is false" do let(:should_run) { false } - it 'skips the after_commit block' do + it "skips the after_commit block" do expect(DB).to_not receive(:after_commit) expect(mailer).to_not receive(:send_emails) @@ -353,7 +353,7 @@ def should_run?(state) = state[:should_run] end end - context 'using :unless and a block' do + context "using :unless and a block" do class UnlessConditionalAfterCommitOperation < MyOperation context :should_skip @@ -375,14 +375,14 @@ def should_skip?(state) = state[:should_skip] end let(:operation) { UnlessConditionalAfterCommitOperation.new(mailer: mailer, should_skip: should_skip) } - let(:params) { { email: 'asd@fgh.net' } } + let(:params) { { email: "asd@fgh.net" } } before { allow(MyModel).to receive(:first).with(params).and_return(model) } - context 'when the condition is false' do + context "when the condition is false" do let(:should_skip) { false } - it 'executes the after_commit block' do + it "executes the after_commit block" do expect(DB).to receive(:after_commit).and_call_original expect(mailer).to receive(:send_emails).with(model) @@ -390,10 +390,10 @@ def should_skip?(state) = state[:should_skip] end end - context 'when the condition is true' do + context "when the condition is true" do let(:should_skip) { true } - it 'skips the after_commit block' do + it "skips the after_commit block" do expect(DB).to_not receive(:after_commit) expect(mailer).to_not receive(:send_emails) @@ -402,7 +402,7 @@ def should_skip?(state) = state[:should_skip] end end - context 'using :if with step name' do + context "using :if with step name" do class IfStepConditionalAfterCommitOperation < MyOperation context :should_run @@ -421,13 +421,13 @@ def send_emails(state) def should_run?(state) = state[:should_run] end - before { allow(MyModel).to receive(:first).with(email: 'asd@fgh.net').and_return(model) } + before { allow(MyModel).to receive(:first).with(email: "asd@fgh.net").and_return(model) } let(:operation) { IfStepConditionalAfterCommitOperation.new(mailer: mailer, should_run: should_run) } - context 'when the condition is true' do + context "when the condition is true" do let(:should_run) { true } - it 'executes the after_commit step' do + it "executes the after_commit step" do expect(DB).to receive(:after_commit).and_call_original expect(mailer).to receive(:send_emails).with(model) @@ -435,10 +435,10 @@ def should_run?(state) = state[:should_run] end end - context 'when the condition is false' do + context "when the condition is false" do let(:should_run) { false } - it 'skips the after_commit step' do + it "skips the after_commit step" do expect(DB).to_not receive(:after_commit) expect(mailer).to_not receive(:send_emails) @@ -447,7 +447,7 @@ def should_run?(state) = state[:should_run] end end - context 'when both :if and :unless are provided' do + context "when both :if and :unless are provided" do class InvalidConditionalAfterCommitOperation < MyOperation process do transaction do @@ -458,14 +458,14 @@ class InvalidConditionalAfterCommitOperation < MyOperation let(:operation) { InvalidConditionalAfterCommitOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('options :if and :unless are mutually exclusive') + .with_message("options :if and :unless are mutually exclusive") end end end - context 'when providing a block and a step' do + context "when providing a block and a step" do class AmbivalentAfterCommitOperation < MyOperation process do transaction do @@ -478,13 +478,13 @@ class AmbivalentAfterCommitOperation < MyOperation let(:operation) { AmbivalentAfterCommitOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('must provide either a step or a block but not both') + .with_message("must provide either a step or a block but not both") end end - context 'when not providing a block nor a step' do + context "when not providing a block nor a step" do class InvalidAfterCommitOperation < MyOperation process do transaction do @@ -495,14 +495,14 @@ class InvalidAfterCommitOperation < MyOperation let(:operation) { InvalidAfterCommitOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error. - with_message('must provide either a step or a block but not both') + with_message("must provide either a step or a block but not both") end end end - describe '#after_rollback' do + describe "#after_rollback" do class LoggerOperation < MyOperation context :logger @@ -523,7 +523,7 @@ def log_error(_) let(:logger) { double } - context 'when providing a block' do + context "when providing a block" do class RollbackWithBlockOperation < LoggerOperation process do transaction do @@ -539,14 +539,14 @@ class RollbackWithBlockOperation < LoggerOperation let(:operation) { RollbackWithBlockOperation.new(logger: logger) } before { expect(DB).to receive(:transaction).and_call_original } - it 'calls after_rollback block when transaction fails' do + it "calls after_rollback block when transaction fails" do expect(MyModel).to receive(:first).with(params).and_return(nil) expect(logger).to receive(:log) expect(operation).to fail_on(params) end - it 'does not call after_rollback block when transaction succeeds' do + it "does not call after_rollback block when transaction succeeds" do expect(MyModel).to receive(:first).with(params).and_return(model) expect(logger).to_not receive(:log) @@ -554,7 +554,7 @@ class RollbackWithBlockOperation < LoggerOperation end end - context 'when providing a step' do + context "when providing a step" do class RollbackStepOperation < LoggerOperation process do transaction do @@ -567,14 +567,14 @@ class RollbackStepOperation < LoggerOperation let(:operation) { RollbackStepOperation.new(logger: logger) } before { expect(DB).to receive(:transaction).and_call_original } - it 'calls after_rollback step when transaction fails' do + it "calls after_rollback step when transaction fails" do expect(MyModel).to receive(:first).with(params).and_return(nil) expect(logger).to receive(:log) expect(operation).to fail_on(params) end - it 'does not call after_rollback step when transaction succeeds' do + it "does not call after_rollback step when transaction succeeds" do expect(MyModel).to receive(:first).with(params).and_return(model) expect(logger).to_not receive(:log) @@ -582,8 +582,8 @@ class RollbackStepOperation < LoggerOperation end end - context 'with conditional execution' do - context 'using :if with a block' do + context "with conditional execution" do + context "using :if with a block" do class IfConditionalAfterRollbackOperation < LoggerOperation context :should_run @@ -601,24 +601,24 @@ def should_run?(state) = state[:should_run] end let(:operation) { IfConditionalAfterRollbackOperation.new(logger: logger, should_run: should_run) } - let(:params) { { email: 'asd@fgh.net' } } + let(:params) { { email: "asd@fgh.net" } } before { allow(MyModel).to receive(:first).with(params).and_return(nil) } - context 'when the condition is true' do + context "when the condition is true" do let(:should_run) { true } - it 'executes the after_rollback block' do + it "executes the after_rollback block" do expect(logger).to receive(:log) expect(operation).to fail_on(params) end end - context 'when the condition is false' do + context "when the condition is false" do let(:should_run) { false } - it 'skips the after_rollback block' do + it "skips the after_rollback block" do expect(DB).to_not receive(:after_rollback) expect(logger).to_not receive(:log) @@ -627,7 +627,7 @@ def should_run?(state) = state[:should_run] end end - context 'using :unless with a block' do + context "using :unless with a block" do class UnlessConditionalAfterRollbackOperation < LoggerOperation context :should_skip @@ -645,24 +645,24 @@ def should_skip?(state) = state[:should_skip] end let(:operation) { UnlessConditionalAfterRollbackOperation.new(logger: logger, should_skip: should_skip) } - let(:params) { { email: 'asd@fgh.net' } } + let(:params) { { email: "asd@fgh.net" } } before { allow(MyModel).to receive(:first).with(params).and_return(nil) } - context 'when the condition is false' do + context "when the condition is false" do let(:should_skip) { false } - it 'executes the after_rollback block' do + it "executes the after_rollback block" do expect(logger).to receive(:log) expect(operation).to fail_on(params) end end - context 'when the condition is true' do + context "when the condition is true" do let(:should_skip) { true } - it 'skips the after_rollback block' do + it "skips the after_rollback block" do expect(DB).to_not receive(:after_rollback) expect(logger).to_not receive(:log) @@ -671,7 +671,7 @@ def should_skip?(state) = state[:should_skip] end end - context 'using :if with step name' do + context "using :if with step name" do class IfStepConditionalAfterRollbackOperation < LoggerOperation context :should_run @@ -686,23 +686,23 @@ class IfStepConditionalAfterRollbackOperation < LoggerOperation def should_run?(state) = state[:should_run] end - before { allow(MyModel).to receive(:first).with(email: 'asd@fgh.net').and_return(nil) } + before { allow(MyModel).to receive(:first).with(email: "asd@fgh.net").and_return(nil) } let(:operation) { IfStepConditionalAfterRollbackOperation.new(logger: logger, should_run: should_run) } - context 'when the condition is true' do + context "when the condition is true" do let(:should_run) { true } - it 'executes the after_rollback step' do + it "executes the after_rollback step" do expect(logger).to receive(:log) expect(operation).to fail_on(params) end end - context 'when the condition is false' do + context "when the condition is false" do let(:should_run) { false } - it 'skips the after_rollback step' do + it "skips the after_rollback step" do expect(DB).to_not receive(:after_rollback) expect(logger).to_not receive(:log) @@ -711,7 +711,7 @@ def should_run?(state) = state[:should_run] end end - context 'when both :if and :unless are provided' do + context "when both :if and :unless are provided" do class InvalidConditionalAfterRollbackOperation < LoggerOperation process do transaction do @@ -722,14 +722,14 @@ class InvalidConditionalAfterRollbackOperation < LoggerOperation let(:operation) { InvalidConditionalAfterRollbackOperation.new(logger: logger) } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('options :if and :unless are mutually exclusive') + .with_message("options :if and :unless are mutually exclusive") end end end - context 'when providing a block and a step' do + context "when providing a block and a step" do class AmbivalentAfterRollbackOperation < MyOperation process do transaction do @@ -742,13 +742,13 @@ class AmbivalentAfterRollbackOperation < MyOperation let(:operation) { AmbivalentAfterRollbackOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('must provide either a step or a block but not both') + .with_message("must provide either a step or a block but not both") end end - context 'when not providing a block nor a step' do + context "when not providing a block nor a step" do class InvalidAfterRollbackOperation < MyOperation process do transaction do @@ -759,13 +759,13 @@ class InvalidAfterRollbackOperation < MyOperation let(:operation) { InvalidAfterRollbackOperation.new } - it 'raises an error' do + it "raises an error" do expect { operation.call(params) }.to raise_error - .with_message('must provide either a step or a block but not both') + .with_message("must provide either a step or a block but not both") end end - context 'when nesting operations with rollback callbacks' do + context "when nesting operations with rollback callbacks" do class InnerFailingOperation < MyOperation context :notifier @@ -818,7 +818,7 @@ def final_step(state)= @notifier.final_step let(:notifier) { spy } let(:operation) { OuterOperationWithRollback.new(notifier: notifier) } - it 'executes rollback callbacks in the correct order when inner operation fails' do + it "executes rollback callbacks in the correct order when inner operation fails" do expect(notifier).to receive(:inner_fail_step) expect(notifier).to receive(:inner_rollback) expect(notifier).to receive(:after_inner_call_step) @@ -838,7 +838,7 @@ def final_step(state)= @notifier.final_step let(:operation) { MyOperation.new } - describe '.model' do + describe ".model" do it "sets the 'result_key' using the model class name" do expect(operation.result_key).to eq(:my_model) end @@ -847,13 +847,13 @@ def final_step(state)= @notifier.final_step expect(operation.model_class).to eq(MyModel) end - context 'when a :search_field option is specified' do + context "when a :search_field option is specified" do it "sets the 'search_field' with the provided value" do expect(operation.search_field).to eq(:email) end end - context 'when no :search_field option is specified' do + context "when no :search_field option is specified" do let(:operation) { PkOperation.new } it "sets the 'search_field' from the model's pk" do @@ -861,7 +861,7 @@ def final_step(state)= @notifier.final_step end end - context 'when the operation is inherited' do + context "when the operation is inherited" do let(:opr_class) { MyOperation } subject(:opr_subclass) { Class.new(opr_class) } @@ -874,16 +874,16 @@ def final_step(state)= @notifier.final_step end end - describe '#db' do - it 'returns the current db form the model class' do + describe "#db" do + it "returns the current db form the model class" do expect(operation.db).to eq(DB) end end - let(:key) { 'some@email.com' } + let(:key) { "some@email.com" } let(:params) { { foo: 3, bar: 4} } - describe '#find_model_with' do + describe "#find_model_with" do it "queries the db through the 'model_class'" do expect(MyModel).to receive(:first).with(email: key) @@ -891,8 +891,8 @@ def final_step(state)= @notifier.final_step end end - describe '#fetch_model' do - let(:other_model) { double(name: 'OtherModel') } + describe "#fetch_model" do + let(:other_model) { double(name: "OtherModel") } let(:dataset) { double(model: other_model) } let(:object) { double } @@ -904,10 +904,10 @@ def final_step(state)= @notifier.final_step context "when proving and external repository through 'from:'" do it "fetches an instance through 'model_class' and sets result key using an overrided search column, input key and 'from' model class" do - expect(other_model).to receive(:first).with(pk: 'foo').and_return(object) + expect(other_model).to receive(:first).with(pk: "foo").and_return(object) expect(MyModel).to_not receive(:first) - state = { input: { myid: 'foo' } } + state = { input: { myid: "foo" } } result = operation .fetch_model(state, from: other_model, using: :myid, search_by: :pk) .value[:my_model] @@ -916,10 +916,10 @@ def final_step(state)= @notifier.final_step end it "fetches an instance through 'model_class' and sets result key using an overrided search column, input key and 'from' dataset" do - expect(dataset).to receive(:first).with(pk: 'foo').and_return(object) + expect(dataset).to receive(:first).with(pk: "foo").and_return(object) expect(MyModel).to_not receive(:first) - state = { input: { myid: 'foo' } } + state = { input: { myid: "foo" } } result = operation .fetch_model(state, from: dataset, using: :myid, search_by: :pk) .value[:my_model] @@ -929,9 +929,9 @@ def final_step(state)= @notifier.final_step end it "fetches an instance through 'model_class' and sets result key using an overrided search column and input key with only :search_by is provided" do - expect(MyModel).to receive(:first).with(name: 'foobar').and_return(object) + expect(MyModel).to receive(:first).with(name: "foobar").and_return(object) - state = { input: { email: 'other@email.com', name: 'foobar' } } + state = { input: { email: "other@email.com", name: "foobar" } } result = operation .fetch_model(state, search_by: :name) .value[:my_model] @@ -940,9 +940,9 @@ def final_step(state)= @notifier.final_step end it "fetches an instance through 'model_class' and sets result key using an overrided input key with but not search column when only :using is provided" do - expect(MyModel).to receive(:first).with(email: 'foobar@mail.com').and_return(object) + expect(MyModel).to receive(:first).with(email: "foobar@mail.com").and_return(object) - state = { input: { email: 'other@email.com', first_email: 'foobar@mail.com' } } + state = { input: { email: "other@email.com", first_email: "foobar@mail.com" } } result = operation .fetch_model(state, using: :first_email) .value[:my_model] @@ -950,7 +950,7 @@ def final_step(state)= @notifier.final_step expect(result).to eq(object) end - it 'returns an error when no instance is found', :aggregate_failures do + it "returns an error when no instance is found", :aggregate_failures do expect(MyModel).to receive(:first).with(email: key).and_return(nil) result = operation.fetch_model({input: {email: key}}) @@ -958,10 +958,10 @@ def final_step(state)= @notifier.final_step expect(result).to be_an(Result::Failure) expect(result.error).to be_an(Pathway::Error) expect(result.error.type).to eq(:not_found) - expect(result.error.message).to eq('My model not found') + expect(result.error.message).to eq("My model not found") end - it 'returns an error without hitting the database when search key is nil', :aggregate_failures do + it "returns an error without hitting the database when search key is nil", :aggregate_failures do expect(MyModel).to_not receive(:first) result = operation.fetch_model({input: {email: nil}}) @@ -969,42 +969,42 @@ def final_step(state)= @notifier.final_step expect(result).to be_an(Result::Failure) expect(result.error).to be_an(Pathway::Error) expect(result.error.type).to eq(:not_found) - expect(result.error.message).to eq('My model not found') + expect(result.error.message).to eq("My model not found") end end - describe '#call' do + describe "#call" do let(:operation) { MyOperation.new(ctx) } - let(:result) { operation.call(email: 'an@email.com') } + let(:result) { operation.call(email: "an@email.com") } let(:fetched_model) { MyModel.new } - context 'when the model is not present at the context' do + context "when the model is not present at the context" do let(:ctx) { {} } it "doesn't include the model's key on the operation's context" do expect(operation.context).to_not include(:my_model) end - it 'fetchs the model from the DB' do - expect(MyModel).to receive(:first).with(email: 'an@email.com').and_return(fetched_model) + it "fetchs the model from the DB" do + expect(MyModel).to receive(:first).with(email: "an@email.com").and_return(fetched_model) expect(result.value).to be(fetched_model) end end - context 'when the model is already present in the context' do + context "when the model is already present in the context" do let(:existing_model) { MyModel.new } let(:ctx) { { my_model: existing_model } } it "includes the model's key on the operation's context" do expect(operation.context).to include(my_model: existing_model) end - it 'uses the model from the context and avoid querying the DB' do + it "uses the model from the context and avoid querying the DB" do expect(MyModel).to_not receive(:first) expect(result.value).to be(existing_model) end - context 'but :fetch_model step specifies overwrite: true' do + context "but :fetch_model step specifies overwrite: true" do class OwOperation < MyOperation process do step :fetch_model, overwrite: true @@ -1013,8 +1013,8 @@ class OwOperation < MyOperation let(:operation) { OwOperation.new(ctx) } - it 'fetches the model from the DB anyway' do - expect(MyModel).to receive(:first).with(email: 'an@email.com').and_return(fetched_model) + it "fetches the model from the DB anyway" do + expect(MyModel).to receive(:first).with(email: "an@email.com").and_return(fetched_model) expect(operation.context).to include(my_model: existing_model) expect(operation.my_model).to be(existing_model) diff --git a/spec/plugins/simple_auth_spec.rb b/spec/plugins/simple_auth_spec.rb index 4ddc382..af62845 100644 --- a/spec/plugins/simple_auth_spec.rb +++ b/spec/plugins/simple_auth_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway module Plugins - describe 'SimpleAuth' do + describe "SimpleAuth" do class AuthOperation < Operation plugin :simple_auth @@ -59,14 +59,14 @@ class AuthOperationWithArray < Operation context "with no options" do it "passes the current result to the authorization block to authorize", :aggregate_failures do - expect(operation.authorize({value: :RESULT})).to be_a_success + expect(operation.authorize({ value: :RESULT })).to be_a_success end end context "with :using argument" do it "passes then value for :key from the context to the authorization block to authorize", :aggregate_failures do - expect(operation.authorize({foo: :RESULT}, using: :foo)).to be_a_success - expect(operation.authorize({foo: :ELSE}, using: :foo)).to be_a_failure + expect(operation.authorize({ foo: :RESULT }, using: :foo)).to be_a_success + expect(operation.authorize({ foo: :ELSE }, using: :foo)).to be_a_failure end end end diff --git a/spec/plugins_spec.rb b/spec/plugins_spec.rb index 667569b..582becc 100644 --- a/spec/plugins_spec.rb +++ b/spec/plugins_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway describe Operation do @@ -29,7 +29,7 @@ def self.apply(opr, bar: nil) end class AnOperation < Operation - plugin SimplePlugin, bar: 'SOME VALUE' + plugin SimplePlugin, bar: "SOME VALUE" end class ASubOperation < AnOperation @@ -38,36 +38,36 @@ class ASubOperation < AnOperation class OtherOperation < Operation end - describe '.plugin' do - it 'includes InstanceMethods module to the class and its subclasses' do + describe ".plugin" do + it "includes InstanceMethods module to the class and its subclasses" do expect(AnOperation.instance_methods).to include(:foo) expect(ASubOperation.instance_methods).to include(:foo) end - it 'includes ClassMethods module to the singleton class and its subclasses' do + it "includes ClassMethods module to the singleton class and its subclasses" do expect(AnOperation.methods).to include(:bar) expect(ASubOperation.methods).to include(:bar) end - it 'includes DSLMethods module to the nested DSL class and its subclasses' do + it "includes DSLMethods module to the nested DSL class and its subclasses" do expect(AnOperation::DSL.instance_methods).to include(:qux) expect(ASubOperation::DSL.instance_methods).to include(:qux) end it "calls 'apply' with its arguments on the Operation where is used" do expect(AnOperation.result_key).to eq(:the_result) - expect(AnOperation.bar).to eq('SOME VALUE') - expect(ASubOperation.bar).to eq('SOME VALUE') + expect(AnOperation.bar).to eq("SOME VALUE") + expect(ASubOperation.bar).to eq("SOME VALUE") end - it 'does not affect main Operation class' do + it "does not affect main Operation class" do expect(Operation.instance_methods).to_not include(:foo) expect(Operation.methods).to_not include(:bar) expect(Operation::DSL.instance_methods).to_not include(:qux) expect(Operation.result_key).to eq(:value) end - it 'does not affect other Operation subclasses' do + it "does not affect other Operation subclasses" do expect(OtherOperation.instance_methods).to_not include(:foo) expect(OtherOperation.methods).to_not include(:bar) expect(OtherOperation::DSL.instance_methods).to_not include(:qux) diff --git a/spec/result_spec.rb b/spec/result_spec.rb index c229086..4291ced 100644 --- a/spec/result_spec.rb +++ b/spec/result_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway describe Result do @@ -51,7 +51,7 @@ module Pathway describe "#then" do let(:callable) { double } - let(:next_result) { Result.success("NEW VALUE")} + let(:next_result) { Result.success("NEW VALUE") } before { expect(callable).to receive(:call).with("VALUE").and_return(next_result) } it "if a block is given it executes it and returns the new result" do @@ -65,7 +65,7 @@ module Pathway describe "#tee" do let(:callable) { double } - let(:next_result) { Result.success("NEW VALUE")} + let(:next_result) { Result.success("NEW VALUE") } before { expect(callable).to receive(:call).with("VALUE").and_return(next_result) } it "if a block is given it executes it and keeps the previous result" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 14d7c71..0f40bdf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,36 +1,36 @@ # frozen_string_literal: true -require 'bundler/setup' +require "bundler/setup" -if ENV['CI'] - require 'simplecov' - require 'simplecov-lcov' +if ENV["CI"] + require "simplecov" + require "simplecov-lcov" SimpleCov.start do SimpleCov::Formatter::LcovFormatter.config do |c| c.report_with_single_file = true - c.single_report_path = 'coverage/lcov.info' + c.single_report_path = "coverage/lcov.info" end formatter SimpleCov::Formatter::LcovFormatter - add_filter '/spec/' - add_filter '/lib/pathway/rspec' + add_filter "/spec/" + add_filter "/lib/pathway/rspec" end end -require 'pathway' -require 'pathway/rspec' -require 'sequel' -require 'pry' -require 'pry-byebug' +require "pathway" +require "pathway/rspec" +require "sequel" +require "pry" +require "pry-byebug" # Load testing support files -Dir[__dir__ + '/support/**/*.rb'].each { |support| require support } +Dir[__dir__ + "/support/**/*.rb"].each { |support| require support } RSpec::Matchers.define_negated_matcher :exclude, :include RSpec.configure do |config| - config.example_status_persistence_file_path = '.rspec_status' + config.example_status_persistence_file_path = ".rspec_status" config.color = true config.tty = true diff --git a/spec/state_pattern_matching_spec.rb b/spec/state_pattern_matching_spec.rb index 8ff2f30..97ca73e 100644 --- a/spec/state_pattern_matching_spec.rb +++ b/spec/state_pattern_matching_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway describe State do @@ -10,11 +10,11 @@ class SimpleOp < Operation end let(:operation) { SimpleOp.new(foo: 20) } - let(:values) { { input: 'some value' } } + let(:values) { { input: "some value" } } subject(:state) { State.new(operation, values) } - describe 'pattern matching' do - context 'internal values' do + describe "pattern matching" do + context "internal values" do let(:result) do case state in input: @@ -22,12 +22,12 @@ class SimpleOp < Operation end end - it 'can extract values from internal state' do - expect(result).to eq('some value') + it "can extract values from internal state" do + expect(result).to eq("some value") end end - context 'operation context values' do + context "operation context values" do let(:result) do case state in foo:, bar: 10 @@ -35,7 +35,7 @@ class SimpleOp < Operation end end - it 'can extract values from operation context' do + it "can extract values from operation context" do expect(result).to eq(20) end end diff --git a/spec/state_spec.rb b/spec/state_spec.rb index 3d4045e..45283aa 100644 --- a/spec/state_spec.rb +++ b/spec/state_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" module Pathway describe State do @@ -10,97 +10,99 @@ class SimpleOp < Operation end let(:operation) { SimpleOp.new(foo: 20) } - let(:values) { { input: 'some value' } } + let(:values) { { input: "some value" } } subject(:state) { State.new(operation, values) } - describe '#initialize' do - it 'initialize its variables from the operation context and values argument' do - expect(state.to_hash).to eq(foo: 20, bar: 10, input: 'some value') + describe "#initialize" do + it "initialize its variables from the operation context and values argument" do + expect(state.to_hash).to eq(foo: 20, bar: 10, input: "some value") end end - describe '#to_hash' do + describe "#to_hash" do let(:result) { state.update(foobar: 25).to_hash } - it 'returns a hash with its internal values' do + it "returns a hash with its internal values" do expect(result).to be_a(Hash) - .and eq(foo: 20, bar: 10, input: 'some value', foobar: 25) + .and eq(foo: 20, bar: 10, input: "some value", foobar: 25) end end - describe '#use' do - before { state.update(val: 'RESULT', foo: 99, bar: 131) } - it 'fails if no block is provided' do - expect { state.use }.to raise_error('a block must be provided') + # rubocop:disable Lint/EmptyBlock, Lint/UnusedBlockArgument + describe "#use" do + before { state.update(val: "RESULT", foo: 99, bar: 131) } + it "fails if no block is provided" do + expect { state.use }.to raise_error("a block must be provided") end - context 'when a block is provided' do - it 'passes specified values using only keyword params', :aggregate_failures do - expect(state.use {|val:| val }).to eq('RESULT') - expect(state.use {|foo:| foo }).to eq(99) - expect(state.use {|val:, bar:| [val, bar] }) - .to eq(['RESULT', 131]) + context "when a block is provided" do + it "passes specified values using only keyword params", :aggregate_failures do + expect(state.use { |val:| val }).to eq("RESULT") + expect(state.use { |foo:| foo }).to eq(99) + expect(state.use { |val:, bar:| [val, bar] }) + .to eq(["RESULT", 131]) end - it 'passes no arguments if no keyword or positional params are defined' do + it "passes no arguments if no keyword or positional params are defined" do expect(state.use { 77 }).to eq(77) end - it 'passes specified values using only positional params', :aggregate_failures do - expect(state.use {|val| val }).to eq('RESULT') - expect(state.use {|foo| foo }).to eq(99) - expect(state.use {|val, bar| [val, bar] }) + it "passes specified values using only positional params", :aggregate_failures do + expect(state.use { |val| val }).to eq("RESULT") + expect(state.use { |foo| foo }).to eq(99) + expect(state.use { |val, bar| [val, bar] }) end - it 'fails if positional and keyword params are both defined', :aggregate_failures do - expect { state.use {|pos, input:| } } - .to raise_error('cannot mix positional and keyword arguments') + it "fails if positional and keyword params are both defined", :aggregate_failures do + expect { state.use { |pos, input:| } } + .to raise_error("cannot mix positional and keyword arguments") end - it 'fails if using rest param', :aggregate_failures do - expect { state.use {|*input| } } - .to raise_error('rest arguments are not supported') - expect { state.use {|input, *args| args } } - .to raise_error('rest arguments are not supported') + it "fails if using rest param", :aggregate_failures do + expect { state.use { |*input| } } + .to raise_error("rest arguments are not supported") + expect { state.use { |input, *args| args } } + .to raise_error("rest arguments are not supported") end - it 'fails if using keyrest param', :aggregate_failures do - expect { state.use {|**kargs| kargs } } - .to raise_error('rest arguments are not supported') - expect { state.use {|input:, **kargs| kargs } } - .to raise_error('rest arguments are not supported') + it "fails if using keyrest param", :aggregate_failures do + expect { state.use { |**kargs| kargs } } + .to raise_error("rest arguments are not supported") + expect { state.use { |input:, **kargs| kargs } } + .to raise_error("rest arguments are not supported") end - context 'that takes a block argument' do - it 'fails if it has positional and keyword params' do - expect { state.use {|input, val:, &bl| } } - .to raise_error('cannot mix positional and keyword arguments') + context "that takes a block argument" do + it "fails if it has positional and keyword params" do + expect { state.use { |input, val:, &_| } } + .to raise_error("cannot mix positional and keyword arguments") end - it 'does not fails if only has keyword params', :aggregate_failures do - expect(state.use {|val:, &bl| val }).to eq('RESULT') - expect(state.use {|val:, &_| val }).to eq('RESULT') - expect(state.use {|&_| 77 }).to eq(77) + it "does not fails if only has keyword params", :aggregate_failures do + expect(state.use { |val:, &_| val }).to eq("RESULT") + expect(state.use { |val:, &_| val }).to eq("RESULT") + expect(state.use { |&_| 77 }).to eq(77) end - it 'does not fails if only has positional params', :aggregate_failures do - expect(state.use {|val, &bl| val }).to eq('RESULT') - expect(state.use {|val, &_| val }).to eq('RESULT') + it "does not fails if only has positional params", :aggregate_failures do + expect(state.use { |val, &_| val }).to eq("RESULT") + expect(state.use { |val, &_| val }).to eq("RESULT") end end end end + # rubocop:enable Lint/EmptyBlock, Lint/UnusedBlockArgument - describe '#update' do + describe "#update" do let(:result) { state.update(qux: 33, quz: 11) } - it 'returns and updated state with the passed values' do + it "returns and updated state with the passed values" do expect(result.to_hash).to include(qux: 33, quz: 11) end end - describe '#result' do + describe "#result" do let(:result) { state.update(the_result: 99).result } - it 'returns the value corresponding to the result key' do + it "returns the value corresponding to the result key" do expect(result).to eq(99) end end