subroutine 4.2.0 → 4.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc5cab16c1cf40e71f51c8572e1a9ecfe7ec0ff7bdabf8ebcae795bd4c30a4f3
4
- data.tar.gz: bee1cf68aba104515cfd2917837d2574a12a61949f2602346da1e7a4d0b029a2
3
+ metadata.gz: 719502dade68ec34e525c97130a82e7ca6b3a5406002882a7916a93ad80d9099
4
+ data.tar.gz: 3eadd2bb114ef5d1724864b67462d0b563f241e21c3b61c92ea47366022aba9a
5
5
  SHA512:
6
- metadata.gz: fcb6f7393b6dfa6525cd344511321f4c3915696311230966ffdbb005128328b0e6d05ebf94b9088911c5d4abf17dd1988bd0d3deb013eaa81d517f1dfdd1c83b
7
- data.tar.gz: 8ee46d11ded0b78432da1e86f7ebd05e30d9a54d55e53b3a336f074a294fc831444bef04381c0659a514c68f19bf6fef13dbd4ff46f321096d179360c10dcf95
6
+ metadata.gz: a57ccde1e224deab1dd2854091b5a1117b026b3feabb2d47626b7227a9905c370fdd95d3aadce201d0f1a84d7409ff225bff20fb9fba07b8444c7b77b069f30c
7
+ data.tar.gz: 750f373e085dfa7a91b78c49f187f9df728a7a03794bde4806d49ae8742c52dcc2f462ba9d4ef2db203e6df190d24dede8f124ef2811af5d5ca4085f7c475411
data/lib/subroutine/op.rb CHANGED
@@ -135,7 +135,7 @@ module Subroutine
135
135
  end
136
136
 
137
137
  if field_config
138
- errors.add(field_config.field_name, error.message)
138
+ errors.add(field_config.field_name, error.type, message: error.message)
139
139
  else
140
140
  errors.add(:base, error_object.full_message(field_name, error.message))
141
141
  end
@@ -13,7 +13,10 @@ module Subroutine
13
13
  end
14
14
  end
15
15
 
16
- DEFAULT_OPTIONS = { required: true }.freeze
16
+ DEFAULT_OPTIONS = {
17
+ required: true,
18
+ lazy: false
19
+ }.freeze
17
20
 
18
21
  attr_reader :output_name
19
22
 
@@ -28,6 +31,10 @@ module Subroutine
28
31
  !!config[:required]
29
32
  end
30
33
 
34
+ def lazy?
35
+ !!config[:lazy]
36
+ end
37
+
31
38
  def inspect
32
39
  "#<#{self.class}:#{object_id} name=#{output_name} config=#{config.inspect}>"
33
40
  end
@@ -10,11 +10,27 @@ module Subroutine
10
10
 
11
11
  extend ActiveSupport::Concern
12
12
 
13
+ class LazyExecutor
14
+ def initialize(value)
15
+ @value_block = value
16
+ @executed = false
17
+ end
18
+
19
+ def value
20
+ return @value if @executed
21
+ @value = @value_block.respond_to?(:call) ? @value_block.call : @value
22
+ @executed = true
23
+ @value
24
+ end
25
+
26
+ def executed?
27
+ @executed
28
+ end
29
+ end
30
+
13
31
  included do
14
32
  class_attribute :output_configurations
15
33
  self.output_configurations = {}
16
-
17
- attr_reader :outputs
18
34
  end
19
35
 
20
36
  module ClassMethods
@@ -39,20 +55,42 @@ module Subroutine
39
55
  @outputs = {} # don't do with_indifferent_access because it will turn provided objects into with_indifferent_access objects, which may not be the desired behavior
40
56
  end
41
57
 
58
+ def outputs
59
+ unless @outputs_executed
60
+ @outputs.each_pair do |key, value|
61
+ @outputs[key] = value.is_a?(LazyExecutor) ? value.value : value
62
+ end
63
+ @outputs_executed = true
64
+ end
65
+
66
+ @outputs
67
+ end
68
+
42
69
  def output(name, value)
43
70
  name = name.to_sym
44
71
  unless output_configurations.key?(name)
45
72
  raise ::Subroutine::Outputs::UnknownOutputError, name
46
73
  end
47
74
 
48
- outputs[name] = value
75
+ @outputs[name] = output_configurations[name].lazy? ? LazyExecutor.new(value) : value
49
76
  end
50
77
 
51
78
  def get_output(name)
52
79
  name = name.to_sym
53
80
  raise ::Subroutine::Outputs::UnknownOutputError, name unless output_configurations.key?(name)
54
81
 
55
- outputs[name]
82
+ output = @outputs[name]
83
+ unless output.is_a?(LazyExecutor)
84
+ output
85
+ else
86
+ # if its not executed, validate the type
87
+ unless output.executed?
88
+ @outputs[name] = output.value
89
+ ensure_output_type_valid!(name)
90
+ end
91
+
92
+ @outputs[name]
93
+ end
56
94
  end
57
95
 
58
96
  def validate_outputs!
@@ -60,21 +98,27 @@ module Subroutine
60
98
  if config.required? && !output_provided?(name)
61
99
  raise ::Subroutine::Outputs::OutputNotSetError, name
62
100
  end
63
- unless valid_output_type?(name)
64
- name = name.to_sym
65
- raise ::Subroutine::Outputs::InvalidOutputTypeError.new(
66
- name: name,
67
- actual_type: outputs[name].class,
68
- expected_type: output_configurations[name][:type]
69
- )
101
+ unless output_configurations[name].lazy?
102
+ ensure_output_type_valid!(name)
70
103
  end
71
104
  end
72
105
  end
73
106
 
107
+ def ensure_output_type_valid!(name)
108
+ return if valid_output_type?(name)
109
+
110
+ name = name.to_sym
111
+ raise ::Subroutine::Outputs::InvalidOutputTypeError.new(
112
+ name: name,
113
+ actual_type: @outputs[name].class,
114
+ expected_type: output_configurations[name][:type]
115
+ )
116
+ end
117
+
74
118
  def output_provided?(name)
75
119
  name = name.to_sym
76
120
 
77
- outputs.key?(name)
121
+ @outputs.key?(name)
78
122
  end
79
123
 
80
124
  def valid_output_type?(name)
@@ -84,9 +128,9 @@ module Subroutine
84
128
 
85
129
  output_configuration = output_configurations[name]
86
130
  return true unless output_configuration[:type]
87
- return true if !output_configuration.required? && outputs[name].nil?
131
+ return true if !output_configuration.required? && @outputs[name].nil?
88
132
 
89
- outputs[name].is_a?(output_configuration[:type])
133
+ @outputs[name].is_a?(output_configuration[:type])
90
134
  end
91
135
  end
92
136
  end
@@ -3,7 +3,7 @@
3
3
  module Subroutine
4
4
 
5
5
  MAJOR = 4
6
- MINOR = 2
6
+ MINOR = 5
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
data/subroutine.gemspec CHANGED
@@ -11,16 +11,23 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ["mike@mnelson.io"]
12
12
  spec.summary = "Feature-driven operation objects."
13
13
  spec.description = "An interface for creating feature-driven operations."
14
- spec.homepage = "https://github.com/mnelson/subroutine"
14
+ spec.homepage = "https://github.com/guideline-tech/subroutine"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0")
17
+ # Specify which files should be added to the gem when it is released.
18
+ spec.files = Dir["lib/**/*"] + Dir["*.gemspec"]
18
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(gemfiles|test)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
+ spec.metadata["rubygems_mfa_required"] = "true"
24
+
22
25
  spec.add_dependency "activemodel", ">= 6.1"
23
26
  spec.add_dependency "activesupport", ">= 6.1"
27
+ spec.add_dependency "base64"
28
+ spec.add_dependency "bigdecimal"
29
+ spec.add_dependency "logger"
30
+ spec.add_dependency "mutex_m"
24
31
 
25
32
  spec.add_development_dependency "actionpack", ">= 6.1"
26
33
  spec.add_development_dependency "byebug"
@@ -29,4 +36,6 @@ Gem::Specification.new do |spec|
29
36
  spec.add_development_dependency "minitest-reporters"
30
37
  spec.add_development_dependency "mocha"
31
38
  spec.add_development_dependency "rake"
39
+
40
+ spec.required_ruby_version = ">= 3.2.0"
32
41
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subroutine
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activemodel
@@ -38,6 +37,62 @@ dependencies:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
39
  version: '6.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: base64
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: bigdecimal
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: logger
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: mutex_m
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
41
96
  - !ruby/object:Gem::Dependency
42
97
  name: actionpack
43
98
  requirement: !ruby/object:Gem::Requirement
@@ -143,27 +198,6 @@ executables: []
143
198
  extensions: []
144
199
  extra_rdoc_files: []
145
200
  files:
146
- - ".bundler-version"
147
- - ".github/CODEOWNERS"
148
- - ".github/dependabot.yml"
149
- - ".github/workflows/build.yml"
150
- - ".gitignore"
151
- - ".ruby-gemset"
152
- - ".ruby-version"
153
- - Appraisals
154
- - CHANGELOG.MD
155
- - Gemfile
156
- - LICENSE.txt
157
- - README.md
158
- - Rakefile
159
- - gemfiles/rails_6.1.gemfile
160
- - gemfiles/rails_6.1.gemfile.lock
161
- - gemfiles/rails_7.0.gemfile
162
- - gemfiles/rails_7.0.gemfile.lock
163
- - gemfiles/rails_7.1.gemfile
164
- - gemfiles/rails_7.1.gemfile.lock
165
- - gemfiles/rails_7.2.gemfile
166
- - gemfiles/rails_7.2.gemfile.lock
167
201
  - lib/subroutine.rb
168
202
  - lib/subroutine/association_fields.rb
169
203
  - lib/subroutine/association_fields/association_type_mismatch_error.rb
@@ -185,19 +219,12 @@ files:
185
219
  - lib/subroutine/type_caster.rb
186
220
  - lib/subroutine/version.rb
187
221
  - subroutine.gemspec
188
- - test/subroutine/association_test.rb
189
- - test/subroutine/auth_test.rb
190
- - test/subroutine/base_test.rb
191
- - test/subroutine/fields_test.rb
192
- - test/subroutine/outputs_test.rb
193
- - test/subroutine/type_caster_test.rb
194
- - test/support/ops.rb
195
- - test/test_helper.rb
196
- homepage: https://github.com/mnelson/subroutine
222
+ homepage: https://github.com/guideline-tech/subroutine
197
223
  licenses:
198
224
  - MIT
199
- metadata: {}
200
- post_install_message:
225
+ metadata:
226
+ allowed_push_host: https://rubygems.org
227
+ rubygems_mfa_required: 'true'
201
228
  rdoc_options: []
202
229
  require_paths:
203
230
  - lib
@@ -205,31 +232,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
232
  requirements:
206
233
  - - ">="
207
234
  - !ruby/object:Gem::Version
208
- version: '0'
235
+ version: 3.2.0
209
236
  required_rubygems_version: !ruby/object:Gem::Requirement
210
237
  requirements:
211
238
  - - ">="
212
239
  - !ruby/object:Gem::Version
213
240
  version: '0'
214
241
  requirements: []
215
- rubygems_version: 3.5.23
216
- signing_key:
242
+ rubygems_version: 3.6.9
217
243
  specification_version: 4
218
244
  summary: Feature-driven operation objects.
219
- test_files:
220
- - gemfiles/rails_6.1.gemfile
221
- - gemfiles/rails_6.1.gemfile.lock
222
- - gemfiles/rails_7.0.gemfile
223
- - gemfiles/rails_7.0.gemfile.lock
224
- - gemfiles/rails_7.1.gemfile
225
- - gemfiles/rails_7.1.gemfile.lock
226
- - gemfiles/rails_7.2.gemfile
227
- - gemfiles/rails_7.2.gemfile.lock
228
- - test/subroutine/association_test.rb
229
- - test/subroutine/auth_test.rb
230
- - test/subroutine/base_test.rb
231
- - test/subroutine/fields_test.rb
232
- - test/subroutine/outputs_test.rb
233
- - test/subroutine/type_caster_test.rb
234
- - test/support/ops.rb
235
- - test/test_helper.rb
245
+ test_files: []
data/.bundler-version DELETED
@@ -1 +0,0 @@
1
- 2.5.22
data/.github/CODEOWNERS DELETED
@@ -1 +0,0 @@
1
- .github/workflows @guideline-tech/engineering
@@ -1,24 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: "github-actions"
4
- directory: "/"
5
- open-pull-requests-limit: 20
6
- schedule:
7
- interval: "daily"
8
- time: "09:00"
9
- timezone: "America/New_York"
10
- commit-message:
11
- prefix: "[github-actions] "
12
- - package-ecosystem: "bundler"
13
- directory: "/"
14
- schedule:
15
- interval: "daily"
16
- time: "08:30"
17
- timezone: "America/New_York"
18
- versioning-strategy: increase
19
- open-pull-requests-limit: 20
20
- insecure-external-code-execution: deny
21
- allow:
22
- - dependency-type: "all"
23
- commit-message:
24
- prefix: "[bundler] "
@@ -1,27 +0,0 @@
1
- name: build
2
- on:
3
- pull_request:
4
- push:
5
- branches:
6
- - main
7
- jobs:
8
- build:
9
- runs-on: ubuntu-latest
10
- strategy:
11
- fail-fast: false
12
- matrix:
13
- ruby-version: [3.0, 3.1, 3.2, 3.3]
14
- steps:
15
- - uses: actions/checkout@v4
16
- with:
17
- show-progress: "false"
18
- - name: get bundler version
19
- run: echo "BUNDLER=$(cat .bundler-version)" >> $GITHUB_ENV
20
- - uses: ruby/setup-ruby@v1
21
- with:
22
- ruby-version: ${{ matrix.ruby-version }}
23
- bundler: ${{ env.BUNDLER }}
24
- bundler-cache: true
25
- - run: bundle install
26
- - run: bundle exec appraisal install
27
- - run: bundle exec appraisal rake test
data/.gitignore DELETED
@@ -1,16 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.bundle
11
- *.so
12
- *.o
13
- *.a
14
- mkmf.log
15
- *.gem
16
- .byebug_history
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- subroutine
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.2.6
data/Appraisals DELETED
@@ -1,19 +0,0 @@
1
- appraise "rails-6.1" do
2
- gem 'activemodel', '~> 6.1.0'
3
- gem 'actionpack', '~> 6.1.0'
4
- end
5
-
6
- appraise "rails-7.0" do
7
- gem 'activemodel', '~> 7.0.0'
8
- gem 'actionpack', '~> 7.0.0'
9
- end
10
-
11
- appraise "rails-7.1" do
12
- gem 'activemodel', '~> 7.1.0'
13
- gem 'actionpack', '~> 7.1.0'
14
- end
15
-
16
- appraise "rails-7.2" do
17
- gem 'activemodel', '~> 7.2.0'
18
- gem 'actionpack', '~> 7.2.0'
19
- end
data/CHANGELOG.MD DELETED
@@ -1,184 +0,0 @@
1
- # Changelog
2
-
3
- ## Subroutine 4.2.0
4
-
5
- If you are using polymorphic association fields, you can now customize how Subroutine
6
- resolves those class names to a ruby class by setting a global callable/lambda/proc:
7
-
8
- ```ruby
9
- ::Subroutine.constantize_polymorphic_class_name = ->(class_name) do
10
- class_name.classify.constantize
11
- end
12
- ```
13
-
14
- ## Subroutine 4.1.4
15
-
16
- Fields using the time/timestamp/datetime caster will now default back to the old behavior, and use a `precision:` option to opt-in to the new behavior introduced in `v4.1.1`.
17
-
18
- `precision: :seconds` will retain the old behavior of always parsing to a new Time object
19
- with floored sub-second precision, but applied more forcefully than before as it would have parsed whatever you passed to it. (This is the default, now.)
20
-
21
- `precision: :high` will now use the new functionality of re-using Time objects when they
22
- are passed in, or if not parsing exactly the provided string as to a Time object.
23
-
24
- ## Subroutine 4.1.1
25
-
26
- Fields using the time/timestamp/datetime caster will now return exactly the passed in value
27
- if it acts like a time object (`acts_like?(:time)`/`acts_like_time?`), instead of serializing
28
- to string and re-parsing to a Time object. This fixes issues with losing usec precision.
29
-
30
- ## Subroutine 4.1.0
31
-
32
- A field can now opt out of the natural assignment behavior of ActiveSupport::HashWithIndifferentAccess. Top level param groups are still accessible via indifferent access but if a field sets the `bypass_indifferent_assignment` option to `true` the HashWithIndifferentAccess assignment behavior will be bypassed in favor of direct Hash-like assignment.
33
-
34
- ```ruby
35
- class MyOp < Subroutine::Op
36
-
37
- object :some_hash
38
- object :some_other_hash, bypass_indifferent_assignment: true
39
-
40
- end
41
- ```
42
-
43
- ## Subroutine 4.0.1
44
-
45
- Association fields can now use `find_by()` instead of `find_by!()` by passing a `raise_on_miss: false` option. This places the responsibility on the op to manage nil cases rather than handling RecordNotFound errors.
46
-
47
- ## Subroutine 4.0
48
-
49
- The `Subroutine::Fields` module now contains a class_attribute that allows the altering of param accessor behaviors. `include_defaults_in_params` is now available to opt into including the default values in usage of the `all_params (alias params)` method. Backwards compatibility is preserved by defaulting the value to `false`. If switched to true, when an input is omitted and the field is configured with a default value, it will be included in the `all_params` object.
50
-
51
- Removed all usage of `ungrouped` params and refactored the storage of grouped params. Params are now stored in either the provided group or the defaults group and accessed via provided_params, params, default_params, and params_with_defaults. Grouped params are accessed the same way but with the group name prefixed eg. `my_private_default_params`.
52
-
53
- Polymorphic association fields now resolve class names via `klass.camelize.constantize`,
54
- previously was `klass.classify.constantize`.
55
-
56
- ## Subroutine 3.0
57
-
58
- Add support for Rails 6.1. Drop support for Rails 6.0 and lower.
59
-
60
- ## Subroutine 2.3
61
-
62
- Support dynamic types for foreign keys on association fields. The class type is used at runtime to determine the casting behavior of the foreign key field.
63
-
64
- ## Subroutine 2.2
65
-
66
- Add `type` validation for Output.
67
-
68
- ## Subroutine 2.0
69
-
70
- The updates between 1.0 and 2.0 are relatively minor and are focused more on cleaning up the codebase and extending the use of the 0.9->1.0 refactor. There are, however, breaking changes to how associations are loaded. The association is no longer loaded via `find()` but rather `find_by!(id:)`. Given this, a major version was released.
71
-
72
- **Note:** 2.0.0 was released with a bug and subsequently yanked. 2.0.1 is the first available 2.x version.
73
-
74
- ## Subroutine 1.0
75
-
76
- A massive refactor took place between 0.9 and 1.0, including breaking changes. The goal was to reduce complexity, simplify backtraces, and increase the overall safety and reliability of the library.
77
-
78
- ### Subroutine::Fields
79
-
80
- `Subroutine::Fields` was completely refactored to manage field declaration, configuration, and access in a more systematic and safer way.
81
-
82
- `Op._fields` was removed in favor of `Op.field_configurations`. `field_configurations` is a hash with keys of the field name and values of `FieldConfiguration` objects. FieldConfiguration objects are SimpleDelegates to the underlying option hashes. They answer questions and provide a mechanism for validating the configuration of a field.
83
-
84
- Fields can be accessed via helpers and accessors can be managed by the field declration. Helpers include `get_field`, `set_field`, and `clear_field`.
85
-
86
- ```ruby
87
- class SomeOp < ::Subroutine::Op
88
- string :foo, read_accessor: field_reader: false, field_writer: true
89
-
90
- def perform
91
- self.foo = "bar"
92
- self.foo # NoMethodError
93
- self.get_field(:foo) # => "bar"
94
- end
95
- end
96
- ```
97
-
98
- Fields can be omitted from mass assignment, meaning they would not be respected via constructor signatures.
99
-
100
- ```ruby
101
- class SomeOp < ::Subroutine::Op
102
- string :foo, mass_assignable: false
103
- def perform
104
- puts foo
105
- end
106
- end
107
-
108
- SomeOp.submit!(foo: "Hello World!") # raises ::Subroutine::Fields::MassAssignmentError
109
- SomeOp.new{|op| op.foo = "Hello World!" }.submit! # prints "Hello World!"
110
- ```
111
-
112
- This is especially useful when dealing with user input and potentially unsafe attributes.
113
-
114
- ```ruby
115
- class UserUpdateOp < ::Op
116
- association :user
117
- string :first_name
118
- string :last_name
119
- integer :credit_balance_cents, mass_assignable: false
120
-
121
- def perform
122
- user.update(params)
123
- end
124
- end
125
-
126
- # some_controller.rb
127
- def update
128
- UserUpdateOp.submit!(params.merge(user: current_user))
129
- end
130
- ```
131
-
132
- Field groups were added as well, allowing you to access subsets of the fields easily.
133
-
134
- ```ruby
135
- class AccountUpdateOp < ::Op
136
- association :account
137
-
138
- with_options group: :user do
139
- string :first_name
140
- string :last_name
141
- date :dob
142
- end
143
-
144
- with_options group: :business do
145
- string :company_name
146
- string :ein
147
- end
148
-
149
- def perform
150
- account.user.update(user_params)
151
- account.business.update(business_params)
152
- end
153
-
154
- end
155
- ```
156
-
157
- ActionController::Parameters from Rails 5+ are now transformed to a hash in `Subroutine::Fields` by default. This means strong parameters are essentially unused when passing `Subroutine::Fields`.
158
-
159
- Read more about field management and access in https://github.com/guideline-tech/subroutine/wiki/Param-Usage
160
-
161
- ### Subroutine::Association
162
-
163
- The `Subroutine::Association` module has been moved to `Subroutine::AssociationFields`.
164
-
165
- Only native types are stored in params now. The objects loaded from associations are stored in an `association_cache`. This ensures access to fields are consistent regardless of the inputs.
166
-
167
- ```ruby
168
- class SomeOp < ::Subroutine::Op
169
- association :user
170
- association :resource, polymorphic: true
171
- end
172
-
173
- user = User.find(4)
174
-
175
- op = SomeOp.new(user: user, resource: user)
176
- op.params #=> { user_id: 4, resource_type: "User", resource_id: 4 }
177
- op.params_with_association #=> { user: <User:103204 @id=4>, resource: <User:103204 @id=4> }
178
-
179
- op = SomeOp.new(user_id: user.id, resource_type: "User", resource_id: user.id)
180
- op.params #=> { user_id: 4, resource_type: "User", resource_id: 4 }
181
- op.params_with_association #=> { user: <User:290053 @id=4>, resource: <User:29042 @id=4> }
182
- ```
183
-
184
- Assignment of associations now validates the type. If an association is not polymorphic, the type will be validated against the expected type.
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in subroutine.gemspec
6
- gemspec
7
-
8
- gem "appraisal"