subroutine 0.7.0 → 0.8.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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +12 -5
- data/Gemfile +1 -1
- data/gemfiles/{am32.gemfile → am50.gemfile} +1 -1
- data/gemfiles/{am30.gemfile → am51.gemfile} +1 -1
- data/gemfiles/{am31.gemfile → am52.gemfile} +1 -1
- data/gemfiles/{am40.gemfile → am60.gemfile} +1 -1
- data/lib/subroutine/fields.rb +147 -0
- data/lib/subroutine/op.rb +15 -131
- data/lib/subroutine/version.rb +1 -1
- data/lib/subroutine.rb +3 -2
- data/subroutine.gemspec +3 -3
- data/test/subroutine/fields_test.rb +54 -0
- metadata +36 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7a1e060b5a23f95d926f8df63e2eb9fc12745a93
|
4
|
+
data.tar.gz: 1205b94faff4d024aa9670cbd0cee003ea3bff5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3313881107db6835f530a41b17f0702f407a2c83413cd7705c00ef4b02017b54566037ad464231651e04948a8416ad4fc02c6939e36d2ac814383fb542829ba
|
7
|
+
data.tar.gz: 75a5d2fe57b634ff5d4e84e105621c769679f065bc1f72c49b835b988972c39fe2d041fbda7f8c8ff99e3c51d79df51ab01ce63299a3b46d88e2a39096d73f2f
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.6
|
data/.travis.yml
CHANGED
@@ -2,12 +2,19 @@ language: ruby
|
|
2
2
|
sudo: false
|
3
3
|
|
4
4
|
rvm:
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.
|
8
|
-
- 2.5.1
|
9
|
-
- jruby
|
5
|
+
- 2.4.6
|
6
|
+
- 2.5.5
|
7
|
+
- 2.6.3
|
10
8
|
|
11
9
|
gemfile:
|
12
10
|
- gemfiles/am41.gemfile
|
13
11
|
- gemfiles/am42.gemfile
|
12
|
+
- gemfiles/am50.gemfile
|
13
|
+
- gemfiles/am51.gemfile
|
14
|
+
- gemfiles/am52.gemfile
|
15
|
+
- gemfiles/am60.gemfile
|
16
|
+
|
17
|
+
matrix:
|
18
|
+
exclude:
|
19
|
+
- rvm: 2.4.6
|
20
|
+
gemfile: gemfiles/am60.gemfile
|
data/Gemfile
CHANGED
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/object/duplicable"
|
5
|
+
require "active_support/core_ext/hash/indifferent_access"
|
6
|
+
require "active_support/core_ext/object/deep_dup"
|
7
|
+
|
8
|
+
require "subroutine/type_caster"
|
9
|
+
require "subroutine/association"
|
10
|
+
|
11
|
+
module Subroutine
|
12
|
+
module Fields
|
13
|
+
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
class_attribute :_fields
|
18
|
+
self._fields = {}
|
19
|
+
attr_reader :original_params
|
20
|
+
attr_reader :params, :defaults
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
# fields can be provided in the following way:
|
25
|
+
# field :field1, :field2
|
26
|
+
# field :field3, :field4, default: 'my default'
|
27
|
+
def field(*fields)
|
28
|
+
options = fields.extract_options!
|
29
|
+
|
30
|
+
fields.each do |f|
|
31
|
+
_field(f, options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias_method :fields, :field
|
35
|
+
|
36
|
+
def inputs_from(*things)
|
37
|
+
options = things.extract_options!
|
38
|
+
excepts = options.key?(:except) ? Array(options.delete(:except)) : nil
|
39
|
+
onlys = options.key?(:only) ? Array(options.delete(:only)) : nil
|
40
|
+
|
41
|
+
things.each do |thing|
|
42
|
+
thing._fields.each_pair do |field_name, opts|
|
43
|
+
next if excepts && excepts.include?(field_name)
|
44
|
+
next if onlys && !onlys.include?(field_name)
|
45
|
+
|
46
|
+
if opts[:association]
|
47
|
+
include ::Subroutine::Association unless included_modules.include?(::Subroutine::Association)
|
48
|
+
association(field_name, opts)
|
49
|
+
else
|
50
|
+
field(field_name, opts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
alias_method :fields_from, :inputs_from
|
56
|
+
|
57
|
+
def respond_to_missing?(method_name, *args, &block)
|
58
|
+
::Subroutine::TypeCaster.casters.key?(method_name.to_sym) || super
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(method_name, *args, &block)
|
62
|
+
caster = ::Subroutine::TypeCaster.casters[method_name.to_sym]
|
63
|
+
if caster
|
64
|
+
options = args.extract_options!
|
65
|
+
options[:type] = method_name.to_sym
|
66
|
+
args.push(options)
|
67
|
+
field(*args, &block)
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def _field(field_name, options = {})
|
76
|
+
self._fields = _fields.merge(field_name.to_sym => options)
|
77
|
+
|
78
|
+
class_eval <<-EV, __FILE__, __LINE__ + 1
|
79
|
+
|
80
|
+
def #{field_name}=(v)
|
81
|
+
config = #{field_name}_config
|
82
|
+
v = ::Subroutine::TypeCaster.cast(v, config)
|
83
|
+
@params["#{field_name}"] = v
|
84
|
+
end
|
85
|
+
|
86
|
+
def #{field_name}
|
87
|
+
@params.has_key?("#{field_name}") ? @params["#{field_name}"] : @defaults["#{field_name}"]
|
88
|
+
end
|
89
|
+
|
90
|
+
def #{field_name}_config
|
91
|
+
_fields[:#{field_name}]
|
92
|
+
end
|
93
|
+
|
94
|
+
EV
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def setup_fields(inputs = {})
|
99
|
+
@original_params = inputs.with_indifferent_access
|
100
|
+
@params = sanitize_params(@original_params)
|
101
|
+
@defaults = sanitize_defaults
|
102
|
+
end
|
103
|
+
|
104
|
+
# check if a specific field was provided
|
105
|
+
def field_provided?(key)
|
106
|
+
@params.key?(key)
|
107
|
+
end
|
108
|
+
|
109
|
+
# if you want to use strong parameters or something in your form object you can do so here.
|
110
|
+
# by default we just slice the inputs to the defined fields
|
111
|
+
def sanitize_params(inputs)
|
112
|
+
out = {}.with_indifferent_access
|
113
|
+
_fields.each_pair do |field, config|
|
114
|
+
next unless inputs.key?(field)
|
115
|
+
|
116
|
+
out[field] = ::Subroutine::TypeCaster.cast(inputs[field], config)
|
117
|
+
end
|
118
|
+
|
119
|
+
out
|
120
|
+
end
|
121
|
+
|
122
|
+
def params_with_defaults
|
123
|
+
@defaults.merge(@params)
|
124
|
+
end
|
125
|
+
|
126
|
+
def sanitize_defaults
|
127
|
+
defaults = {}.with_indifferent_access
|
128
|
+
|
129
|
+
_fields.each_pair do |field, config|
|
130
|
+
next if config[:default].nil?
|
131
|
+
|
132
|
+
deflt = config[:default]
|
133
|
+
if deflt.respond_to?(:call)
|
134
|
+
deflt = deflt.call
|
135
|
+
elsif deflt.duplicable? # from active_support
|
136
|
+
# Some classes of default values need to be duplicated, or the instance field value will end up referencing
|
137
|
+
# the class global default value, and potentially modify it.
|
138
|
+
deflt = deflt.deep_dup # from active_support
|
139
|
+
end
|
140
|
+
defaults[field] = ::Subroutine::TypeCaster.cast(deflt, config)
|
141
|
+
end
|
142
|
+
|
143
|
+
defaults
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
data/lib/subroutine/op.rb
CHANGED
@@ -1,50 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'active_support/core_ext/object/duplicable'
|
5
|
-
require 'active_support/core_ext/object/deep_dup'
|
6
|
-
require 'active_model'
|
3
|
+
require "active_model"
|
7
4
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
5
|
+
require "subroutine/fields"
|
6
|
+
require "subroutine/failure"
|
7
|
+
require "subroutine/filtered_errors"
|
8
|
+
require "subroutine/output_not_set_error"
|
9
|
+
require "subroutine/unknown_output_error"
|
13
10
|
|
14
11
|
module Subroutine
|
15
12
|
class Op
|
13
|
+
|
14
|
+
include ::Subroutine::Fields
|
16
15
|
include ::ActiveModel::Model
|
17
16
|
include ::ActiveModel::Validations::Callbacks
|
18
17
|
|
19
18
|
DEFAULT_OUTPUT_OPTIONS = {
|
20
|
-
required: true
|
19
|
+
required: true,
|
21
20
|
}.freeze
|
22
21
|
|
23
22
|
class << self
|
24
|
-
::Subroutine::TypeCaster.casters.each_key do |caster|
|
25
|
-
next if method_defined?(caster)
|
26
|
-
|
27
|
-
class_eval <<-EV, __FILE__, __LINE__ + 1
|
28
|
-
def #{caster}(*args)
|
29
|
-
options = args.extract_options!
|
30
|
-
options[:type] = #{caster.inspect}
|
31
|
-
args.push(options)
|
32
|
-
field(*args)
|
33
|
-
end
|
34
|
-
EV
|
35
|
-
end
|
36
|
-
|
37
|
-
# fields can be provided in the following way:
|
38
|
-
# field :field1, :field2
|
39
|
-
# field :field3, :field4, default: 'my default'
|
40
|
-
def field(*fields)
|
41
|
-
options = fields.extract_options!
|
42
|
-
|
43
|
-
fields.each do |f|
|
44
|
-
_field(f, options)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
alias fields field
|
48
23
|
|
49
24
|
def outputs(*names)
|
50
25
|
options = names.extract_options!
|
@@ -66,33 +41,6 @@ module Subroutine
|
|
66
41
|
end
|
67
42
|
alias ignore_errors ignore_error
|
68
43
|
|
69
|
-
def inputs_from(*ops)
|
70
|
-
options = ops.extract_options!
|
71
|
-
excepts = options.key?(:except) ? Array(options.delete(:except)) : nil
|
72
|
-
onlys = options.key?(:only) ? Array(options.delete(:only)) : nil
|
73
|
-
|
74
|
-
ops.each do |op|
|
75
|
-
op._fields.each_pair do |field_name, op_options|
|
76
|
-
next if excepts && excepts.include?(field_name)
|
77
|
-
next if onlys && !onlys.include?(field_name)
|
78
|
-
|
79
|
-
if op_options[:association]
|
80
|
-
include ::Subroutine::Association unless included_modules.include?(::Subroutine::Association)
|
81
|
-
association(field_name, op_options)
|
82
|
-
else
|
83
|
-
field(field_name, op_options)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def inherited(child)
|
90
|
-
super
|
91
|
-
child._fields = _fields.dup
|
92
|
-
child._error_map = _error_map.dup
|
93
|
-
child._error_ignores = _error_ignores.dup
|
94
|
-
end
|
95
|
-
|
96
44
|
def submit!(*args)
|
97
45
|
op = new(*args)
|
98
46
|
op.submit!
|
@@ -109,59 +57,36 @@ module Subroutine
|
|
109
57
|
protected
|
110
58
|
|
111
59
|
def _field(field_name, options = {})
|
112
|
-
|
60
|
+
result = super(field_name, options)
|
113
61
|
|
114
62
|
if options[:aka]
|
115
63
|
Array(options[:aka]).each do |as|
|
116
|
-
_error_map
|
64
|
+
self._error_map = _error_map.merge(as.to_sym => field_name.to_sym)
|
117
65
|
end
|
118
66
|
end
|
119
67
|
|
120
68
|
_ignore_errors(field_name) if options[:ignore_errors]
|
121
69
|
|
122
|
-
|
123
|
-
|
124
|
-
def #{field_name}=(v)
|
125
|
-
config = #{field_name}_config
|
126
|
-
v = ::Subroutine::TypeCaster.cast(v, config)
|
127
|
-
@params["#{field_name}"] = v
|
128
|
-
end
|
129
|
-
|
130
|
-
def #{field_name}
|
131
|
-
@params.has_key?("#{field_name}") ? @params["#{field_name}"] : @defaults["#{field_name}"]
|
132
|
-
end
|
133
|
-
|
134
|
-
def #{field_name}_config
|
135
|
-
_fields[:#{field_name}]
|
136
|
-
end
|
137
|
-
|
138
|
-
EV
|
70
|
+
result
|
139
71
|
end
|
140
72
|
|
141
73
|
def _ignore_errors(field_name)
|
142
|
-
_error_ignores
|
74
|
+
self._error_ignores = _error_ignores.merge(field_name.to_sym => true)
|
143
75
|
end
|
76
|
+
|
144
77
|
end
|
145
78
|
|
146
79
|
class_attribute :_outputs
|
147
80
|
self._outputs = {}
|
148
81
|
|
149
|
-
class_attribute :_fields
|
150
|
-
self._fields = {}
|
151
|
-
|
152
82
|
class_attribute :_error_map
|
153
83
|
self._error_map = {}
|
154
84
|
|
155
85
|
class_attribute :_error_ignores
|
156
86
|
self._error_ignores = {}
|
157
87
|
|
158
|
-
attr_reader :original_params
|
159
|
-
attr_reader :params, :defaults
|
160
|
-
|
161
88
|
def initialize(inputs = {})
|
162
|
-
|
163
|
-
@params = sanitize_params(@original_params)
|
164
|
-
@defaults = sanitize_defaults
|
89
|
+
setup_fields(inputs)
|
165
90
|
@outputs = {}
|
166
91
|
end
|
167
92
|
|
@@ -217,10 +142,6 @@ module Subroutine
|
|
217
142
|
end
|
218
143
|
end
|
219
144
|
|
220
|
-
def params_with_defaults
|
221
|
-
@defaults.merge(@params)
|
222
|
-
end
|
223
|
-
|
224
145
|
protected
|
225
146
|
|
226
147
|
# these enable you to 1) add log output or 2) add performance monitoring such as skylight.
|
@@ -248,11 +169,6 @@ module Subroutine
|
|
248
169
|
raise NotImplementedError
|
249
170
|
end
|
250
171
|
|
251
|
-
# check if a specific field was provided
|
252
|
-
def field_provided?(key)
|
253
|
-
@params.key?(key)
|
254
|
-
end
|
255
|
-
|
256
172
|
# applies the errors in error_object to self
|
257
173
|
# returns false so failure cases can end with this invocation
|
258
174
|
def inherit_errors(error_object)
|
@@ -273,37 +189,5 @@ module Subroutine
|
|
273
189
|
false
|
274
190
|
end
|
275
191
|
|
276
|
-
# if you want to use strong parameters or something in your form object you can do so here.
|
277
|
-
# by default we just slice the inputs to the defined fields
|
278
|
-
def sanitize_params(inputs)
|
279
|
-
out = {}.with_indifferent_access
|
280
|
-
_fields.each_pair do |field, config|
|
281
|
-
next unless inputs.key?(field)
|
282
|
-
|
283
|
-
out[field] = ::Subroutine::TypeCaster.cast(inputs[field], config)
|
284
|
-
end
|
285
|
-
|
286
|
-
out
|
287
|
-
end
|
288
|
-
|
289
|
-
def sanitize_defaults
|
290
|
-
defaults = {}.with_indifferent_access
|
291
|
-
|
292
|
-
_fields.each_pair do |field, config|
|
293
|
-
next if config[:default].nil?
|
294
|
-
|
295
|
-
deflt = config[:default]
|
296
|
-
if deflt.respond_to?(:call)
|
297
|
-
deflt = deflt.call
|
298
|
-
elsif deflt.duplicable? # from active_support
|
299
|
-
# Some classes of default values need to be duplicated, or the instance field value will end up referencing
|
300
|
-
# the class global default value, and potentially modify it.
|
301
|
-
deflt = deflt.deep_dup # from active_support
|
302
|
-
end
|
303
|
-
defaults[field] = ::Subroutine::TypeCaster.cast(deflt, config)
|
304
|
-
end
|
305
|
-
|
306
|
-
defaults
|
307
|
-
end
|
308
192
|
end
|
309
193
|
end
|
data/lib/subroutine/version.rb
CHANGED
data/lib/subroutine.rb
CHANGED
data/subroutine.gemspec
CHANGED
@@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "activemodel", ">= 4.0.0"
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler"
|
24
|
-
spec.add_development_dependency "rake"
|
25
|
-
|
23
|
+
spec.add_development_dependency "bundler"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "m"
|
26
26
|
spec.add_development_dependency "minitest"
|
27
27
|
spec.add_development_dependency "minitest-reporters"
|
28
28
|
spec.add_development_dependency "mocha"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
require "subroutine/fields"
|
5
|
+
|
6
|
+
module Subroutine
|
7
|
+
class FieldsTest < TestCase
|
8
|
+
|
9
|
+
class Whatever
|
10
|
+
|
11
|
+
include Subroutine::Fields
|
12
|
+
|
13
|
+
string :foo, default: "foo"
|
14
|
+
integer :bar, default: -> { 3 }
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
setup_fields(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_fields_are_configured
|
23
|
+
assert_equal 2, Whatever._fields.size
|
24
|
+
assert_equal :string, Whatever._fields[:foo][:type]
|
25
|
+
assert_equal :integer, Whatever._fields[:bar][:type]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_field_defaults_are_handled
|
29
|
+
instance = Whatever.new
|
30
|
+
assert_equal "foo", instance.foo
|
31
|
+
assert_equal 3, instance.bar
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_fields_can_be_provided
|
35
|
+
instance = Whatever.new(foo: "abc", bar: nil)
|
36
|
+
assert_equal "abc", instance.foo
|
37
|
+
assert_nil instance.bar
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_field_provided
|
41
|
+
instance = Whatever.new(foo: "abc")
|
42
|
+
assert_equal true, instance.field_provided?(:foo)
|
43
|
+
assert_equal false, instance.field_provided?(:bar)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_params
|
47
|
+
instance = Whatever.new(foo: "abc")
|
48
|
+
assert_equal({ "foo" => "abc" }, instance.params)
|
49
|
+
assert_equal({ "foo" => "abc", "bar" => 3 }, instance.params_with_defaults)
|
50
|
+
assert_equal({ "foo" => "foo", "bar" => 3 }, instance.defaults)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subroutine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Nelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -28,30 +28,44 @@ dependencies:
|
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: m
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: minitest
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,16 +123,17 @@ files:
|
|
109
123
|
- LICENSE.txt
|
110
124
|
- README.md
|
111
125
|
- Rakefile
|
112
|
-
- gemfiles/am30.gemfile
|
113
|
-
- gemfiles/am31.gemfile
|
114
|
-
- gemfiles/am32.gemfile
|
115
|
-
- gemfiles/am40.gemfile
|
116
126
|
- gemfiles/am41.gemfile
|
117
127
|
- gemfiles/am42.gemfile
|
128
|
+
- gemfiles/am50.gemfile
|
129
|
+
- gemfiles/am51.gemfile
|
130
|
+
- gemfiles/am52.gemfile
|
131
|
+
- gemfiles/am60.gemfile
|
118
132
|
- lib/subroutine.rb
|
119
133
|
- lib/subroutine/association.rb
|
120
134
|
- lib/subroutine/auth.rb
|
121
135
|
- lib/subroutine/failure.rb
|
136
|
+
- lib/subroutine/fields.rb
|
122
137
|
- lib/subroutine/filtered_errors.rb
|
123
138
|
- lib/subroutine/op.rb
|
124
139
|
- lib/subroutine/output_not_set_error.rb
|
@@ -129,6 +144,7 @@ files:
|
|
129
144
|
- test/subroutine/association_test.rb
|
130
145
|
- test/subroutine/auth_test.rb
|
131
146
|
- test/subroutine/base_test.rb
|
147
|
+
- test/subroutine/fields_test.rb
|
132
148
|
- test/subroutine/type_caster_test.rb
|
133
149
|
- test/support/ops.rb
|
134
150
|
- test/test_helper.rb
|
@@ -152,20 +168,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
168
|
version: '0'
|
153
169
|
requirements: []
|
154
170
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.
|
171
|
+
rubygems_version: 2.6.14.4
|
156
172
|
signing_key:
|
157
173
|
specification_version: 4
|
158
174
|
summary: Feature-driven operation objects.
|
159
175
|
test_files:
|
160
|
-
- gemfiles/am30.gemfile
|
161
|
-
- gemfiles/am31.gemfile
|
162
|
-
- gemfiles/am32.gemfile
|
163
|
-
- gemfiles/am40.gemfile
|
164
176
|
- gemfiles/am41.gemfile
|
165
177
|
- gemfiles/am42.gemfile
|
178
|
+
- gemfiles/am50.gemfile
|
179
|
+
- gemfiles/am51.gemfile
|
180
|
+
- gemfiles/am52.gemfile
|
181
|
+
- gemfiles/am60.gemfile
|
166
182
|
- test/subroutine/association_test.rb
|
167
183
|
- test/subroutine/auth_test.rb
|
168
184
|
- test/subroutine/base_test.rb
|
185
|
+
- test/subroutine/fields_test.rb
|
169
186
|
- test/subroutine/type_caster_test.rb
|
170
187
|
- test/support/ops.rb
|
171
188
|
- test/test_helper.rb
|