active_interaction 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +11 -12
  4. data/lib/active_interaction/base.rb +2 -0
  5. data/lib/active_interaction/errors.rb +15 -15
  6. data/lib/active_interaction/filters/hash_filter.rb +5 -1
  7. data/lib/active_interaction/version.rb +1 -1
  8. data/spec/active_interaction/array_input_spec.rb +1 -3
  9. data/spec/active_interaction/base_spec.rb +1 -2
  10. data/spec/active_interaction/concerns/active_modelable_spec.rb +2 -4
  11. data/spec/active_interaction/concerns/active_recordable_spec.rb +1 -3
  12. data/spec/active_interaction/concerns/hashable_spec.rb +1 -3
  13. data/spec/active_interaction/concerns/missable_spec.rb +1 -3
  14. data/spec/active_interaction/concerns/runnable_spec.rb +1 -3
  15. data/spec/active_interaction/errors_spec.rb +29 -2
  16. data/spec/active_interaction/filter/column_spec.rb +1 -3
  17. data/spec/active_interaction/filter_spec.rb +1 -3
  18. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -3
  19. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -3
  20. data/spec/active_interaction/filters/array_filter_spec.rb +1 -3
  21. data/spec/active_interaction/filters/boolean_filter_spec.rb +1 -3
  22. data/spec/active_interaction/filters/date_filter_spec.rb +1 -3
  23. data/spec/active_interaction/filters/date_time_filter_spec.rb +1 -3
  24. data/spec/active_interaction/filters/decimal_filter_spec.rb +1 -3
  25. data/spec/active_interaction/filters/file_filter_spec.rb +1 -3
  26. data/spec/active_interaction/filters/float_filter_spec.rb +1 -2
  27. data/spec/active_interaction/filters/hash_filter_spec.rb +1 -3
  28. data/spec/active_interaction/filters/integer_filter_spec.rb +1 -3
  29. data/spec/active_interaction/filters/interface_filter_spec.rb +1 -3
  30. data/spec/active_interaction/filters/object_filter_spec.rb +1 -3
  31. data/spec/active_interaction/filters/record_filter_spec.rb +1 -3
  32. data/spec/active_interaction/filters/string_filter_spec.rb +1 -3
  33. data/spec/active_interaction/filters/symbol_filter_spec.rb +1 -3
  34. data/spec/active_interaction/filters/time_filter_spec.rb +1 -3
  35. data/spec/active_interaction/grouped_input_spec.rb +1 -3
  36. data/spec/active_interaction/hash_input_spec.rb +1 -3
  37. data/spec/active_interaction/i18n_spec.rb +2 -4
  38. data/spec/active_interaction/inputs_spec.rb +1 -3
  39. data/spec/active_interaction/integration/array_interaction_spec.rb +1 -2
  40. data/spec/active_interaction/integration/boolean_interaction_spec.rb +8 -2
  41. data/spec/active_interaction/integration/date_interaction_spec.rb +1 -3
  42. data/spec/active_interaction/integration/date_time_interaction_spec.rb +1 -3
  43. data/spec/active_interaction/integration/file_interaction_spec.rb +1 -2
  44. data/spec/active_interaction/integration/float_interaction_spec.rb +1 -3
  45. data/spec/active_interaction/integration/hash_interaction_spec.rb +33 -3
  46. data/spec/active_interaction/integration/integer_interaction_spec.rb +1 -3
  47. data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -2
  48. data/spec/active_interaction/integration/object_interaction_spec.rb +1 -3
  49. data/spec/active_interaction/integration/record_integration_spec.rb +1 -3
  50. data/spec/active_interaction/integration/string_interaction_spec.rb +1 -3
  51. data/spec/active_interaction/integration/symbol_interaction_spec.rb +1 -3
  52. data/spec/active_interaction/integration/time_interaction_spec.rb +1 -3
  53. data/spec/active_interaction/modules/validation_spec.rb +1 -3
  54. data/spec/spec_helper.rb +2 -0
  55. data/spec/support/concerns.rb +1 -1
  56. data/spec/support/filters.rb +2 -2
  57. data/spec/support/interactions.rb +2 -2
  58. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b90b2dc28188b224ed0aa986afb739056dbd2407061da2dfee81b825c5674ca9
4
- data.tar.gz: 755707a0f9554cee89a08567245f3d78d597a8b7ae7ec671c3eb572f4dd5a881
3
+ metadata.gz: 9b454bfd8df636194b206bcac24dba1e52dd88b6cd5b45322e6d769c7eeebe8d
4
+ data.tar.gz: 8624a4b45f3f198528a24e7994af331fde5d66c7c7b732db2e1efeb63a72c9cc
5
5
  SHA512:
6
- metadata.gz: d24433ef35282b38531e2e18c1e426f69f9cc71692fdb2d96e21f3c420b56a6bb42c3f473b255890b457ab3d1764d6b132ec7f30260437d732ced70b083d217a
7
- data.tar.gz: dd2ce32a0c59afa9f5fe1a8134aa82e98404b1e0d5a3a3801b8dd7a726f75f28d16de46c72687c3e5f807db0576936e0a34abe3b26201dd2c58c90c798df10d5
6
+ metadata.gz: cc07f6e2d9b5cea926350d72a061be59b0101a301ba1bee2a6cfab10485a4b83bed85445efc02f919936f2e3b34edc7bdf7890ca04869db5a58cc88cc2bb1d6e
7
+ data.tar.gz: 4b582ae18497b4abb6f3a287ec3bfaff08fbc0cbef7e0ab33c35a9345ebd1fd9fd437f96b870e88760dfa82a056467df17b18b326698310e711ced0c4b5a0996
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [5.3.0][] (2023-05-06)
2
+
3
+ ## Added
4
+
5
+ - Added predicate methods for boolean values. Thanks @heka1024
6
+
7
+ ## Fixed
8
+
9
+ - [#554][] - Non-detailed error should not lose options when merged.
10
+ - [#553][] - Improve error handling and documentation for hash filter defaults.
11
+
1
12
  # [5.2.0][] (2022-10-22)
2
13
 
3
14
  ## Added
@@ -1361,3 +1372,5 @@ Example.run
1361
1372
  [#537]: https://github.com/AaronLasseigne/active_interaction/issues/537
1362
1373
  [#539]: https://github.com/AaronLasseigne/active_interaction/issues/539
1363
1374
  [#545]: https://github.com/AaronLasseigne/active_interaction/issues/545
1375
+ [#554]: https://github.com/AaronLasseigne/active_interaction/issues/554
1376
+ [#553]: https://github.com/AaronLasseigne/active_interaction/issues/553
data/README.md CHANGED
@@ -2,16 +2,11 @@
2
2
 
3
3
  ActiveInteraction manages application-specific business logic.
4
4
  It's an implementation of service objects designed to blend seamlessly into Rails.
5
+ It also helps you write safer code by validating that your inputs conform to your expectations.
6
+ If ActiveModel deals with your nouns, then ActiveInteraction handles your verbs.
5
7
 
6
8
  [![Version](https://img.shields.io/gem/v/active_interaction.svg?style=flat-square)](https://rubygems.org/gems/active_interaction)
7
- [![Test](https://img.shields.io/github/workflow/status/AaronLasseigne/active_interaction/Test?label=Test&style=flat-square)](https://github.com/AaronLasseigne/active_interaction/actions?query=workflow%3ATest)
8
-
9
- ---
10
-
11
- ActiveInteraction gives you a place to put your business logic. It also helps
12
- you write safer code by validating that your inputs conform to your
13
- expectations. If ActiveModel deals with your nouns, then ActiveInteraction
14
- handles your verbs.
9
+ [![Test](https://img.shields.io/github/actions/workflow/status/AaronLasseigne/active_interaction/test.yml?label=Test&style=flat-square&branch=main)](https://github.com/AaronLasseigne/active_interaction/actions?query=workflow%3ATest)
15
10
 
16
11
  - [Installation](#installation)
17
12
  - [Basic usage](#basic-usage)
@@ -65,13 +60,13 @@ handles your verbs.
65
60
  Add it to your Gemfile:
66
61
 
67
62
  ``` rb
68
- gem 'active_interaction', '~> 5.2'
63
+ gem 'active_interaction', '~> 5.3'
69
64
  ```
70
65
 
71
66
  Or install it manually:
72
67
 
73
68
  ``` sh
74
- $ gem install active_interaction --version '~> 5.2'
69
+ $ gem install active_interaction --version '~> 5.3'
75
70
  ```
76
71
 
77
72
  This project uses [Semantic Versioning][]. Check out [GitHub releases][] for a
@@ -296,12 +291,15 @@ Boolean filters convert the strings `"1"`, `"true"`, and `"on"`
296
291
  (case-insensitive) into `true`. They also convert `"0"`, `"false"`, and `"off"`
297
292
  into `false`. Blank strings will be treated as `nil`.
298
293
 
294
+ Boolean values can be accessed using the filter name but can also be checked
295
+ using a predicate method of the same name.
296
+
299
297
  ``` rb
300
298
  class BooleanInteraction < ActiveInteraction::Base
301
299
  boolean :kool_aid
302
300
 
303
301
  def execute
304
- 'Oh yeah!' if kool_aid
302
+ 'Oh yeah!' if kool_aid? # could also use `kool_aid`
305
303
  end
306
304
  end
307
305
 
@@ -360,7 +358,8 @@ HashInteraction.run!(preferences: { newsletter: true, 'sweepstakes' => false })
360
358
 
361
359
  Setting default hash values can be tricky. The default value has to be either
362
360
  `nil` or `{}`. Use `nil` to make the hash optional. Use `{}` if you want to set
363
- some defaults for values inside the hash.
361
+ some defaults for values inside the hash. If any nested filter uses a
362
+ [lazy default](#defaults) then the hash must also use a lazy default.
364
363
 
365
364
  ``` rb
366
365
  hash :optional,
@@ -147,6 +147,8 @@ module ActiveInteraction
147
147
 
148
148
  attr_accessor attribute
149
149
 
150
+ alias_method "#{attribute}?", attribute if filter.is_a?(BooleanFilter)
151
+
150
152
  eagerly_evaluate_default(filter)
151
153
  end
152
154
 
@@ -11,7 +11,15 @@ module ActiveInteraction
11
11
  #
12
12
  # @return [Errors]
13
13
  def merge!(other)
14
- merge_details!(other)
14
+ other.messages.each do |attribute, messages|
15
+ messages.zip(other.details[attribute]) do |message, detail|
16
+ if detailed_error?(detail)
17
+ merge_detail!(attribute, detail, message)
18
+ else
19
+ merge_message!(attribute, detail, message)
20
+ end
21
+ end
22
+ end
15
23
 
16
24
  self
17
25
  end
@@ -31,24 +39,16 @@ module ActiveInteraction
31
39
  detail[:error].is_a?(Symbol)
32
40
  end
33
41
 
34
- def merge_message!(attribute, message)
42
+ def merge_message!(attribute, detail, message)
43
+ options = detail.dup
44
+ options.delete(:error)
45
+
35
46
  unless attribute?(attribute)
36
47
  message = full_message(attribute, message)
37
48
  attribute = :base
38
49
  end
39
- add(attribute, message) unless added?(attribute, message)
40
- end
41
50
 
42
- def merge_details!(other)
43
- other.messages.each do |attribute, messages|
44
- messages.zip(other.details[attribute]) do |message, detail|
45
- if detailed_error?(detail)
46
- merge_detail!(attribute, detail, message)
47
- else
48
- merge_message!(attribute, message)
49
- end
50
- end
51
- end
51
+ add(attribute, message, **options) unless added?(attribute, message, **options)
52
52
  end
53
53
 
54
54
  def merge_detail!(attribute, detail, message)
@@ -58,7 +58,7 @@ module ActiveInteraction
58
58
 
59
59
  add(attribute, error, **options.merge(message: message)) unless added?(attribute, error, **options)
60
60
  else
61
- merge_message!(attribute, message)
61
+ merge_message!(attribute, detail, message)
62
62
  end
63
63
  end
64
64
  end
@@ -25,7 +25,7 @@ module ActiveInteraction
25
25
 
26
26
  register :hash
27
27
 
28
- def process(value, context)
28
+ def process(value, context) # rubocop:disable Metrics/AbcSize
29
29
  input = super
30
30
 
31
31
  return HashInput.new(self, value: input.value, error: input.errors.first) if input.errors.first
@@ -36,6 +36,10 @@ module ActiveInteraction
36
36
  children = {}
37
37
 
38
38
  filters.each do |name, filter|
39
+ if filter.options[:default].is_a?(Proc) && !options[:default].is_a?(Proc)
40
+ raise InvalidDefaultError, "#{self.name}: must use a lazy default if any nested filter uses a lazy default"
41
+ end
42
+
39
43
  filter.process(input.value[name], context).tap do |result|
40
44
  value[name] = result.value
41
45
  children[name.to_sym] = result
@@ -4,5 +4,5 @@ module ActiveInteraction
4
4
  # The version number.
5
5
  #
6
6
  # @return [Gem::Version]
7
- VERSION = Gem::Version.new('5.2.0')
7
+ VERSION = Gem::Version.new('5.3.0')
8
8
  end
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::ArrayInput do
1
+ RSpec.describe ActiveInteraction::ArrayInput do
4
2
  subject(:input) do
5
3
  described_class.new(filter,
6
4
  value: value,
@@ -1,4 +1,3 @@
1
- require 'spec_helper'
2
1
  require 'action_controller'
3
2
  require 'active_support/core_ext/kernel/reporting'
4
3
 
@@ -34,7 +33,7 @@ InterruptInteraction = Class.new(TestInteraction) do
34
33
  end
35
34
  end
36
35
 
37
- describe ActiveInteraction::Base do
36
+ RSpec.describe ActiveInteraction::Base do
38
37
  subject(:interaction) { described_class.new(inputs) }
39
38
 
40
39
  include_context 'interactions'
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- shared_examples_for 'ActiveModel' do
1
+ RSpec.shared_examples_for 'ActiveModel' do
4
2
  it 'includes ActiveModel::Conversion' do
5
3
  expect(subject).to be_a_kind_of ActiveModel::Conversion
6
4
  end
@@ -14,7 +12,7 @@ shared_examples_for 'ActiveModel' do
14
12
  end
15
13
  end
16
14
 
17
- describe ActiveInteraction::ActiveModelable do
15
+ RSpec.describe ActiveInteraction::ActiveModelable do
18
16
  include_context 'concerns', described_class
19
17
 
20
18
  it_behaves_like 'ActiveModel'
@@ -1,10 +1,8 @@
1
- require 'spec_helper'
2
-
3
1
  InteractionWithFloatFilter = Class.new(TestInteraction) do
4
2
  float :thing
5
3
  end
6
4
 
7
- describe ActiveInteraction::ActiveRecordable do
5
+ RSpec.describe ActiveInteraction::ActiveRecordable do
8
6
  include_context 'interactions'
9
7
 
10
8
  let(:described_class) { InteractionWithFloatFilter }
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Hashable do
1
+ RSpec.describe ActiveInteraction::Hashable do
4
2
  include_context 'concerns', described_class
5
3
 
6
4
  describe '#hash(*args, &block)' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Missable do
1
+ RSpec.describe ActiveInteraction::Missable do
4
2
  include_context 'concerns', described_class
5
3
 
6
4
  describe '#respond_to?(slug, include_all = false)' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Runnable do
1
+ RSpec.describe ActiveInteraction::Runnable do
4
2
  include_context 'concerns', described_class
5
3
 
6
4
  class WrappableFailingInteraction # rubocop:disable Lint/ConstantDefinitionInBlock
@@ -1,4 +1,3 @@
1
- require 'spec_helper'
2
1
  require 'active_record'
3
2
  require 'sqlite3'
4
3
 
@@ -7,7 +6,7 @@ ActiveRecord::Base.establish_connection(
7
6
  database: ':memory:'
8
7
  )
9
8
 
10
- describe ActiveInteraction::Errors do
9
+ RSpec.describe ActiveInteraction::Errors do
11
10
  subject(:errors) { described_class.new(klass.new) }
12
11
 
13
12
  let(:klass) do
@@ -39,6 +38,20 @@ describe ActiveInteraction::Errors do
39
38
  errors.merge!(other)
40
39
  expect(errors.messages[:attribute]).to eql ['is invalid']
41
40
  end
41
+
42
+ context 'that provides other options' do
43
+ let(:value) { SecureRandom.hex }
44
+ let(:error_name) { 'Some error' }
45
+
46
+ before do
47
+ other.add(:base, error_name, value: value)
48
+ end
49
+
50
+ it 'adds the error' do
51
+ errors.merge!(other)
52
+ expect(errors.details[:base]).to eql [{ error: error_name, value: value }]
53
+ end
54
+ end
42
55
  end
43
56
 
44
57
  context 'with a detailed error' do
@@ -91,6 +104,20 @@ describe ActiveInteraction::Errors do
91
104
  expect(errors.messages[:base]).to eql [message]
92
105
  end
93
106
  end
107
+
108
+ context 'that provides other options' do
109
+ let(:value) { SecureRandom.hex }
110
+ let(:error_name) { :some_error }
111
+
112
+ before do
113
+ other.add(:base, error_name, value: value)
114
+ end
115
+
116
+ it 'adds the error' do
117
+ errors.merge!(other)
118
+ expect(errors.details[:base]).to eql [{ error: error_name, value: value }]
119
+ end
120
+ end
94
121
  end
95
122
 
96
123
  context 'with an interpolated detailed error' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Filter::Column do
1
+ RSpec.describe ActiveInteraction::Filter::Column do
4
2
  subject(:column) { described_class.intern(type) }
5
3
 
6
4
  let(:type) { :float }
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Filter, :filter do
1
+ RSpec.describe ActiveInteraction::Filter, :filter do
4
2
  include_context 'filters'
5
3
 
6
4
  describe '#database_column_type' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::AbstractDateTimeFilter, :filter do
1
+ RSpec.describe ActiveInteraction::AbstractDateTimeFilter, :filter do
4
2
  include_context 'filters'
5
3
 
6
4
  describe '#process' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::AbstractNumericFilter, :filter do
1
+ RSpec.describe ActiveInteraction::AbstractNumericFilter, :filter do
4
2
  include_context 'filters'
5
3
 
6
4
  describe '#process' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::ArrayFilter, :filter do
1
+ RSpec.describe ActiveInteraction::ArrayFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::BooleanFilter, :filter do
1
+ RSpec.describe ActiveInteraction::BooleanFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::DateFilter, :filter do
1
+ RSpec.describe ActiveInteraction::DateFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::DateTimeFilter, :filter do
1
+ RSpec.describe ActiveInteraction::DateTimeFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::DecimalFilter, :filter do
1
+ RSpec.describe ActiveInteraction::DecimalFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::FileFilter, :filter do
1
+ RSpec.describe ActiveInteraction::FileFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,7 +1,6 @@
1
1
  require 'bigdecimal'
2
- require 'spec_helper'
3
2
 
4
- describe ActiveInteraction::FloatFilter, :filter do
3
+ RSpec.describe ActiveInteraction::FloatFilter, :filter do
5
4
  include_context 'filters'
6
5
  it_behaves_like 'a filter'
7
6
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::HashFilter, :filter do
1
+ RSpec.describe ActiveInteraction::HashFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::IntegerFilter, :filter do
1
+ RSpec.describe ActiveInteraction::IntegerFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,10 +1,8 @@
1
- require 'spec_helper'
2
-
3
1
  module InterfaceModule; end
4
2
 
5
3
  class InterfaceClass; end # rubocop:disable Lint/EmptyClass
6
4
 
7
- describe ActiveInteraction::InterfaceFilter, :filter do
5
+ RSpec.describe ActiveInteraction::InterfaceFilter, :filter do
8
6
  include_context 'filters'
9
7
  it_behaves_like 'a filter' do
10
8
  let(:name) { :interface_module }
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  class ObjectThing
4
2
  def self.converter(_)
5
3
  @converter ||= new
@@ -13,7 +11,7 @@ end
13
11
  class ObjectThings; end # rubocop:disable Lint/EmptyClass
14
12
  BackupObjectThing = ObjectThing
15
13
 
16
- describe ActiveInteraction::ObjectFilter, :filter do
14
+ RSpec.describe ActiveInteraction::ObjectFilter, :filter do
17
15
  include_context 'filters'
18
16
  before do
19
17
  options[:class] = ObjectThing
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  class RecordThing
4
2
  def self.find(_)
5
3
  raise 'error'
@@ -21,7 +19,7 @@ end
21
19
  class RecordThings; end # rubocop:disable Lint/EmptyClass
22
20
  BackupRecordThing = RecordThing
23
21
 
24
- describe ActiveInteraction::RecordFilter, :filter do
22
+ RSpec.describe ActiveInteraction::RecordFilter, :filter do
25
23
  include_context 'filters'
26
24
  before do
27
25
  options[:class] = RecordThing
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::StringFilter, :filter do
1
+ RSpec.describe ActiveInteraction::StringFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::SymbolFilter, :filter do
1
+ RSpec.describe ActiveInteraction::SymbolFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::TimeFilter, :filter do
1
+ RSpec.describe ActiveInteraction::TimeFilter, :filter do
4
2
  include_context 'filters'
5
3
  it_behaves_like 'a filter'
6
4
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::GroupedInput do
1
+ RSpec.describe ActiveInteraction::GroupedInput do
4
2
  subject(:grouped_input) { described_class.new }
5
3
 
6
4
  it 'subclasses OpenStruct' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::HashInput do
1
+ RSpec.describe ActiveInteraction::HashInput do
4
2
  subject(:input) do
5
3
  described_class.new(filter,
6
4
  value: value,
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction do
1
+ RSpec.describe ActiveInteraction do
4
2
  context 'I18n.load_path' do
5
3
  it 'contains localization file paths' do
6
4
  expect(I18n.load_path)
@@ -20,7 +18,7 @@ TYPES = ActiveInteraction::Filter
20
18
  .keys
21
19
  .map(&:to_s)
22
20
 
23
- describe I18nInteraction do
21
+ RSpec.describe I18nInteraction do
24
22
  include_context 'interactions'
25
23
 
26
24
  shared_examples 'translation' do |locale|
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Inputs do
1
+ RSpec.describe ActiveInteraction::Inputs do
4
2
  subject(:inputs) { described_class.new(args, base_class.new) }
5
3
 
6
4
  let(:args) { {} }
@@ -1,4 +1,3 @@
1
- require 'spec_helper'
2
1
  require 'active_record'
3
2
  require 'sqlite3'
4
3
 
@@ -29,7 +28,7 @@ ArrayInteraction = Class.new(TestInteraction) do
29
28
  end
30
29
  end
31
30
 
32
- describe ArrayInteraction do
31
+ RSpec.describe ArrayInteraction do
33
32
  include_context 'interactions'
34
33
  it_behaves_like 'an interaction', :array, -> { [] }
35
34
  it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }, ->(result) { result.to_a }
@@ -1,5 +1,11 @@
1
- require 'spec_helper'
1
+ BooleanInteraction = Class.new(TestInteraction) do
2
+ boolean :x
3
+ end
2
4
 
3
- describe 'BooleanInteraction' do
5
+ RSpec.describe BooleanInteraction do
4
6
  it_behaves_like 'an interaction', :boolean, -> { [false, true].sample }
7
+
8
+ it 'responds to #x?' do
9
+ expect(described_class.new).to respond_to(:x?)
10
+ end
5
11
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'DateInteraction' do
1
+ RSpec.describe 'DateInteraction' do
4
2
  it_behaves_like 'an interaction', :date, -> { Date.today }
5
3
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'DateTimeInteraction' do
1
+ RSpec.describe 'DateTimeInteraction' do
4
2
  it_behaves_like 'an interaction', :date_time, -> { DateTime.now }
5
3
  end
@@ -1,11 +1,10 @@
1
- require 'spec_helper'
2
1
  require 'action_dispatch'
3
2
 
4
3
  FileInteraction = Class.new(TestInteraction) do
5
4
  file :a
6
5
  end
7
6
 
8
- describe FileInteraction do
7
+ RSpec.describe FileInteraction do
9
8
  include_context 'interactions'
10
9
  it_behaves_like 'an interaction', :file, -> { File.open(__FILE__) }
11
10
 
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'FloatInteraction' do
1
+ RSpec.describe 'FloatInteraction' do
4
2
  it_behaves_like 'an interaction', :float, -> { rand }
5
3
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  HashInteraction = Class.new(TestInteraction) do
4
2
  hash :a do
5
3
  hash :x
@@ -9,7 +7,7 @@ HashInteraction = Class.new(TestInteraction) do
9
7
  end
10
8
  end
11
9
 
12
- describe HashInteraction do
10
+ RSpec.describe HashInteraction do
13
11
  include_context 'interactions'
14
12
  it_behaves_like 'an interaction', :hash, -> { {} }
15
13
 
@@ -73,4 +71,36 @@ describe HashInteraction do
73
71
  end.to raise_error ActiveInteraction::InvalidDefaultError
74
72
  end
75
73
  end
74
+
75
+ context 'with a default' do
76
+ context 'with a lazy nested default' do
77
+ it 'raises an error' do
78
+ expect do
79
+ Class.new(ActiveInteraction::Base) do
80
+ hash :b, default: {} do
81
+ hash :x, default: -> { {} }
82
+ end
83
+ end
84
+ end.to raise_error ActiveInteraction::InvalidDefaultError
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'with a lazy default' do
90
+ context 'with a lazy nested default' do
91
+ it 'returns the correct value' do
92
+ klass = Class.new(ActiveInteraction::Base) do
93
+ hash :b, default: -> { {} } do
94
+ hash :x, default: -> { {} }
95
+ end
96
+
97
+ def execute
98
+ b
99
+ end
100
+ end
101
+
102
+ expect(klass.run!).to eql('x' => {})
103
+ end
104
+ end
105
+ end
76
106
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'IntegerInteraction' do
1
+ RSpec.describe 'IntegerInteraction' do
4
2
  it_behaves_like 'an interaction', :integer, -> { rand(1 << 16) }
5
3
  end
@@ -1,4 +1,3 @@
1
- require 'spec_helper'
2
1
  require 'json'
3
2
  require 'yaml'
4
3
 
@@ -6,7 +5,7 @@ InterfaceInteraction = Class.new(TestInteraction) do
6
5
  interface :anything, methods: []
7
6
  end
8
7
 
9
- describe InterfaceInteraction do
8
+ RSpec.describe InterfaceInteraction do
10
9
  include_context 'interactions'
11
10
  it_behaves_like 'an interaction',
12
11
  :interface,
@@ -1,10 +1,8 @@
1
- require 'spec_helper'
2
-
3
1
  ObjectInteraction = Class.new(TestInteraction) do
4
2
  object :object
5
3
  end
6
4
 
7
- describe ObjectInteraction do
5
+ RSpec.describe ObjectInteraction do
8
6
  include_context 'interactions'
9
7
  it_behaves_like 'an interaction', :object, -> { // }, class: Regexp
10
8
 
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'RecordIntegration' do
1
+ RSpec.describe 'RecordIntegration' do
4
2
  it_behaves_like 'an interaction', :record, -> { Encoding::US_ASCII }, class: Encoding
5
3
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'StringInteraction' do
1
+ RSpec.describe 'StringInteraction' do
4
2
  it_behaves_like 'an interaction', :string, -> { SecureRandom.hex }
5
3
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
- describe 'SymbolInteraction' do
1
+ RSpec.describe 'SymbolInteraction' do
4
2
  it_behaves_like 'an interaction', :symbol, -> { SecureRandom.hex.to_sym }
5
3
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  TimeWithZone = Class.new do
4
2
  attr_reader :time
5
3
 
@@ -26,7 +24,7 @@ TimeInteraction = Class.new(TestInteraction) do
26
24
  time :a
27
25
  end
28
26
 
29
- describe TimeInteraction do
27
+ RSpec.describe TimeInteraction do
30
28
  include_context 'interactions'
31
29
  it_behaves_like 'an interaction', :time, -> { Time.now }
32
30
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveInteraction::Validation do
1
+ RSpec.describe ActiveInteraction::Validation do
4
2
  describe '.validate(context, filters, inputs)' do
5
3
  let(:inputs) { {} }
6
4
  let(:filter) { ActiveInteraction::Filter.new(:name, {}) }
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,8 @@ RSpec.configure do |config|
10
10
  config.run_all_when_everything_filtered = true
11
11
  config.filter_run_including :focus
12
12
 
13
+ config.disable_monkey_patching!
14
+
13
15
  config.before(:suite) do
14
16
  if ActiveRecord.respond_to?(:index_nested_attribute_errors)
15
17
  ActiveRecord.index_nested_attribute_errors = false
@@ -1,4 +1,4 @@
1
- shared_context 'concerns' do |concern|
1
+ RSpec.shared_context 'concerns' do |concern|
2
2
  subject(:instance) { klass.new }
3
3
 
4
4
  let(:klass) do
@@ -1,4 +1,4 @@
1
- shared_context 'filters' do
1
+ RSpec.shared_context 'filters' do
2
2
  subject(:filter) { described_class.new(name, options, &block) }
3
3
 
4
4
  let(:block) { nil }
@@ -18,7 +18,7 @@ shared_context 'filters' do
18
18
  end
19
19
  end
20
20
 
21
- shared_examples_for 'a filter' do
21
+ RSpec.shared_examples_for 'a filter' do
22
22
  include_context 'filters'
23
23
 
24
24
  describe '.factory' do
@@ -8,13 +8,13 @@ TestInteraction = Class.new(ActiveInteraction::Base) do
8
8
  end
9
9
  end
10
10
 
11
- shared_context 'interactions' do
11
+ RSpec.shared_context 'interactions' do
12
12
  let(:inputs) { {} }
13
13
  let(:outcome) { described_class.run(inputs) }
14
14
  let(:result) { outcome.result }
15
15
  end
16
16
 
17
- shared_examples_for 'an interaction' do |type, generator, adjust_output = nil, **filter_options|
17
+ RSpec.shared_examples_for 'an interaction' do |type, generator, adjust_output = nil, **filter_options|
18
18
  include_context 'interactions'
19
19
 
20
20
  let(:described_class) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_interaction
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Lasseigne
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-10-22 00:00:00.000000000 Z
12
+ date: 2023-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -322,7 +322,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
322
322
  - !ruby/object:Gem::Version
323
323
  version: '0'
324
324
  requirements: []
325
- rubygems_version: 3.3.7
325
+ rubygems_version: 3.4.1
326
326
  signing_key:
327
327
  specification_version: 4
328
328
  summary: Manage application specific business logic.