runger_actions 0.19.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 +7 -0
- data/.github/dependabot.yml +13 -0
- data/.github/workflows/ruby.yml +25 -0
- data/.gitignore +11 -0
- data/.release_assistant.yml +3 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +225 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +268 -0
- data/LICENSE.txt +21 -0
- data/README.md +662 -0
- data/RELEASING.md +7 -0
- data/Rakefile +8 -0
- data/bin/_guard-core +28 -0
- data/bin/console +15 -0
- data/bin/guard +28 -0
- data/bin/release +28 -0
- data/bin/rspec +30 -0
- data/bin/rubocop +30 -0
- data/bin/setup +8 -0
- data/lib/generators/runger_actions/action/USAGE +8 -0
- data/lib/generators/runger_actions/action/action_generator.rb +13 -0
- data/lib/generators/runger_actions/action/templates/action.rb +12 -0
- data/lib/runger_actions/base.rb +229 -0
- data/lib/runger_actions/error.rb +3 -0
- data/lib/runger_actions/result.rb +23 -0
- data/lib/runger_actions/version.rb +5 -0
- data/lib/runger_actions.rb +18 -0
- data/runger_actions.gemspec +34 -0
- metadata +131 -0
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'runger_actions'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/guard
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'guard' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
21
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'bundler/setup'
|
27
|
+
|
28
|
+
load Gem.bin_path('guard', 'guard')
|
data/bin/release
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'release' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
21
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'bundler/setup'
|
27
|
+
|
28
|
+
load Gem.bin_path('release_assistant', 'release')
|
data/bin/rspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort(<<~ERROR)
|
21
|
+
Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.
|
23
|
+
ERROR
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rubygems'
|
28
|
+
require 'bundler/setup'
|
29
|
+
|
30
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/rubocop
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort(<<~ERROR)
|
21
|
+
Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.
|
23
|
+
ERROR
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rubygems'
|
28
|
+
require 'bundler/setup'
|
29
|
+
|
30
|
+
load Gem.bin_path('rubocop', 'rubocop')
|
data/bin/setup
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
module RungerActions::Generators ; end
|
6
|
+
|
7
|
+
class RungerActions::Generators::ActionGenerator < Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
9
|
+
|
10
|
+
def create_policy
|
11
|
+
template('action.rb', File.join('app/actions', class_path, "#{file_name}.rb"))
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class <%= class_name %> < ApplicationAction
|
4
|
+
# requires :email, String
|
5
|
+
|
6
|
+
# returns :user, User
|
7
|
+
|
8
|
+
def execute
|
9
|
+
# result.user = User.create!(email: email)
|
10
|
+
# NewUserMailer.user_created(result.user.id).deliver_later
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RungerActions::Base
|
4
|
+
extend Memoist
|
5
|
+
|
6
|
+
class << self
|
7
|
+
extend Memoist
|
8
|
+
|
9
|
+
def run!(params)
|
10
|
+
new!(params).run!
|
11
|
+
end
|
12
|
+
|
13
|
+
def new!(params)
|
14
|
+
action = new(params)
|
15
|
+
if action.valid?
|
16
|
+
action
|
17
|
+
else
|
18
|
+
raise(RungerActions::InvalidParam, action.errors.full_messages.join(', '))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def requires(param_name, *shape_descriptions, &blk)
|
23
|
+
required_params[param_name] = Shaped::Shape(*shape_descriptions)
|
24
|
+
|
25
|
+
shape_description = shape_descriptions.first if shape_descriptions.size == 1
|
26
|
+
if (
|
27
|
+
shape_description.is_a?(Class) && (shape_description < ActiveRecord::Base) && blk.present?
|
28
|
+
)
|
29
|
+
register_validator_klass(param_name, shape_description, blk)
|
30
|
+
end
|
31
|
+
|
32
|
+
define_reader_method(param_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def define_reader_method(param_name)
|
36
|
+
define_method(param_name) do
|
37
|
+
@params[param_name]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def register_validator_klass(param_name, param_klass, blk)
|
42
|
+
validator_klass = const_set("#{param_name.to_s.camelize}Validator", Class.new)
|
43
|
+
validator_klass.include(ActiveModel::Model)
|
44
|
+
validator_klass.attr_accessor(*param_klass.column_names)
|
45
|
+
validator_klass.class_eval(&blk)
|
46
|
+
validators[param_name] = validator_klass
|
47
|
+
end
|
48
|
+
|
49
|
+
def returns(param_name, *shape_descriptions)
|
50
|
+
shape = Shaped::Shape(*shape_descriptions)
|
51
|
+
promised_values[param_name] = shape
|
52
|
+
result_klass.class_eval do
|
53
|
+
define_method(param_name) do
|
54
|
+
@return_values[param_name]
|
55
|
+
end
|
56
|
+
|
57
|
+
define_method("#{param_name}=") do |value|
|
58
|
+
if locked?
|
59
|
+
raise(RungerActions::MutatingLockedResult, <<~ERROR.squish)
|
60
|
+
You are attempting to assign a value to an instance of #{self.class} outside of the
|
61
|
+
#{self.class.module_parent}#execute method. This is not allowed; you may only assign
|
62
|
+
values to the `result` within the #execute method.
|
63
|
+
ERROR
|
64
|
+
end
|
65
|
+
|
66
|
+
if !shape.matched_by?(value)
|
67
|
+
raise(RungerActions::TypeMismatch, <<~ERROR.squish)
|
68
|
+
Attemted to assign an invalid value for `result.#{param_name}` ; expected an object
|
69
|
+
shaped like #{shape} but got #{value.inspect}
|
70
|
+
ERROR
|
71
|
+
end
|
72
|
+
|
73
|
+
@return_values[param_name] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fails_with(error_type)
|
79
|
+
result_klass.class_eval do
|
80
|
+
define_method("#{error_type}!") do |error_message = nil|
|
81
|
+
@failure = error_type
|
82
|
+
@error_message = error_message
|
83
|
+
if @action.raise_on_failure?
|
84
|
+
raise(
|
85
|
+
RungerActions::RuntimeFailure,
|
86
|
+
"#{@action.class.name} action failed with `#{error_type}`",
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
define_method("#{error_type}?") do
|
92
|
+
@failure == error_type
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
memoize \
|
98
|
+
def result_klass
|
99
|
+
const_set(:Result, Class.new(RungerActions::Result))
|
100
|
+
end
|
101
|
+
|
102
|
+
memoize \
|
103
|
+
def required_params
|
104
|
+
{}
|
105
|
+
end
|
106
|
+
|
107
|
+
memoize \
|
108
|
+
def promised_values
|
109
|
+
{}
|
110
|
+
end
|
111
|
+
|
112
|
+
memoize \
|
113
|
+
def validators
|
114
|
+
{}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
attr_reader :errors
|
119
|
+
|
120
|
+
# We can't specify keyword arguments for this method because we don't know which keywords/params
|
121
|
+
# the method will need to accept; that's defined by the user.
|
122
|
+
#
|
123
|
+
# rubocop:disable Style/OptionHash
|
124
|
+
def initialize(params = {})
|
125
|
+
@params = params
|
126
|
+
@errors = ActiveModel::Errors.new(self)
|
127
|
+
validate_required_params!
|
128
|
+
end
|
129
|
+
# rubocop:enable Style/OptionHash
|
130
|
+
|
131
|
+
def run(raise_on_failure: false)
|
132
|
+
@raise_on_failure = raise_on_failure
|
133
|
+
if !respond_to?(:execute)
|
134
|
+
raise(RungerActions::ExecuteNotImplemented, <<~ERROR.squish)
|
135
|
+
All RungerActions classes must implement an #execute instance method, but #{self.class}
|
136
|
+
fails to do so.
|
137
|
+
ERROR
|
138
|
+
end
|
139
|
+
|
140
|
+
execute
|
141
|
+
result.lock!
|
142
|
+
verify_promised_return_values! if result.success?
|
143
|
+
result
|
144
|
+
end
|
145
|
+
|
146
|
+
def run!
|
147
|
+
if valid?
|
148
|
+
run(raise_on_failure: true)
|
149
|
+
else
|
150
|
+
raise(RungerActions::InvalidParam, @errors.full_messages.join(', '))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def valid?
|
155
|
+
run_custom_validations
|
156
|
+
@errors.blank?
|
157
|
+
end
|
158
|
+
|
159
|
+
def raise_on_failure?
|
160
|
+
!!@raise_on_failure
|
161
|
+
end
|
162
|
+
|
163
|
+
memoize \
|
164
|
+
def result
|
165
|
+
self.class.result_klass.new(action: self)
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def verify_promised_return_values!
|
171
|
+
missing_return_values = self.class.promised_values.keys - result.return_values.keys
|
172
|
+
if missing_return_values.any?
|
173
|
+
violation_messages =
|
174
|
+
missing_return_values.map do |missing_return_value|
|
175
|
+
expected_shape = self.class.promised_values[missing_return_value]
|
176
|
+
"`#{missing_return_value}` (should be shaped like #{expected_shape})"
|
177
|
+
end
|
178
|
+
|
179
|
+
raise(RungerActions::MissingResultValue, <<~ERROR.squish)
|
180
|
+
#{self.class.name} failed to set all promised return values on its `result`. The
|
181
|
+
following were missing on the `result`: #{violation_messages.join(', ')}.
|
182
|
+
ERROR
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def run_custom_validations
|
187
|
+
self.class.required_params.each_key do |param_name|
|
188
|
+
validator_klass = self.class.validators[param_name]
|
189
|
+
next if validator_klass.nil?
|
190
|
+
|
191
|
+
model_instance = @params[param_name]
|
192
|
+
validator_instance = validator_klass.new(model_instance.attributes)
|
193
|
+
if !validator_instance.valid?
|
194
|
+
@errors = validator_instance.errors
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def validate_required_params!
|
200
|
+
missing_params = self.class.required_params.keys - @params.keys
|
201
|
+
if missing_params.any?
|
202
|
+
raise(RungerActions::MissingParam, <<~ERROR.squish)
|
203
|
+
Required param(s) #{missing_params.map { "`#{_1}`" }.join(', ')} were not provided to
|
204
|
+
the #{self.class} action.
|
205
|
+
ERROR
|
206
|
+
end
|
207
|
+
|
208
|
+
type_mismatches = []
|
209
|
+
self.class.required_params.each do |param_name, shape|
|
210
|
+
value = @params[param_name]
|
211
|
+
if !shape.matched_by?(value)
|
212
|
+
type_mismatches << [param_name, shape, value]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
if type_mismatches.any?
|
217
|
+
messages =
|
218
|
+
type_mismatches.map do |param_name, shape, value|
|
219
|
+
<<~MESSAGE.squish
|
220
|
+
`#{param_name}` is expected to be shaped like #{shape}, but was
|
221
|
+
`#{value.is_a?(String) ? value.inspect : value}`
|
222
|
+
MESSAGE
|
223
|
+
end
|
224
|
+
raise(RungerActions::TypeMismatch, <<~ERROR.squish)
|
225
|
+
One or more required params are of the wrong type: #{messages.join(' ; ')}.
|
226
|
+
ERROR
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RungerActions::Result
|
4
|
+
attr_reader :error_message, :return_values
|
5
|
+
|
6
|
+
def initialize(action:)
|
7
|
+
@action = action
|
8
|
+
@return_values = {}
|
9
|
+
@failure = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def lock!
|
13
|
+
@locked = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def locked?
|
17
|
+
@locked == true
|
18
|
+
end
|
19
|
+
|
20
|
+
def success?
|
21
|
+
@failure.nil?
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RungerActions ; end
|
4
|
+
|
5
|
+
require 'active_model'
|
6
|
+
require 'active_record'
|
7
|
+
require 'active_support/all'
|
8
|
+
require 'memoist'
|
9
|
+
require 'shaped'
|
10
|
+
Dir["#{File.dirname(__FILE__)}/runger_actions/**/*.rb"].each { |file| require file }
|
11
|
+
|
12
|
+
class RungerActions::ExecuteNotImplemented < RungerActions::Error ; end
|
13
|
+
class RungerActions::InvalidParam < RungerActions::Error ; end
|
14
|
+
class RungerActions::MissingParam < RungerActions::Error ; end
|
15
|
+
class RungerActions::MissingResultValue < RungerActions::Error ; end
|
16
|
+
class RungerActions::MutatingLockedResult < RungerActions::Error ; end
|
17
|
+
class RungerActions::RuntimeFailure < RungerActions::Error ; end
|
18
|
+
class RungerActions::TypeMismatch < RungerActions::Error ; end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/runger_actions/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'runger_actions'
|
7
|
+
spec.version = RungerActions::VERSION
|
8
|
+
spec.authors = ['David Runger']
|
9
|
+
spec.email = ['davidjrunger@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'Organize (and validate) the business logic of your Rails application.'
|
12
|
+
spec.description = 'Organize (and validate) the business logic of your Rails application.'
|
13
|
+
spec.homepage = 'https://github.com/davidrunger/runger_actions'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.2.0')
|
16
|
+
|
17
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/davidrunger/runger_actions'
|
20
|
+
spec.metadata['changelog_uri'] =
|
21
|
+
'https://github.com/davidrunger/runger_actions/blob/master/CHANGELOG.md'
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files =
|
26
|
+
Dir.chdir(File.expand_path(__dir__)) do
|
27
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
28
|
+
end
|
29
|
+
spec.require_paths = ['lib']
|
30
|
+
|
31
|
+
spec.add_runtime_dependency('memoist', '~> 0.16')
|
32
|
+
spec.add_runtime_dependency('rails', '>= 6', '< 8')
|
33
|
+
spec.add_runtime_dependency('shaped', '>= 0.9', '< 0.11')
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: runger_actions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.19.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Runger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-05-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: memoist
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.16'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '8'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '6'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '8'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: shaped
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.9'
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0.11'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.9'
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0.11'
|
67
|
+
description: Organize (and validate) the business logic of your Rails application.
|
68
|
+
email:
|
69
|
+
- davidjrunger@gmail.com
|
70
|
+
executables: []
|
71
|
+
extensions: []
|
72
|
+
extra_rdoc_files: []
|
73
|
+
files:
|
74
|
+
- ".github/dependabot.yml"
|
75
|
+
- ".github/workflows/ruby.yml"
|
76
|
+
- ".gitignore"
|
77
|
+
- ".release_assistant.yml"
|
78
|
+
- ".rspec"
|
79
|
+
- ".rubocop.yml"
|
80
|
+
- ".ruby-version"
|
81
|
+
- CHANGELOG.md
|
82
|
+
- Gemfile
|
83
|
+
- Gemfile.lock
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- RELEASING.md
|
87
|
+
- Rakefile
|
88
|
+
- bin/_guard-core
|
89
|
+
- bin/console
|
90
|
+
- bin/guard
|
91
|
+
- bin/release
|
92
|
+
- bin/rspec
|
93
|
+
- bin/rubocop
|
94
|
+
- bin/setup
|
95
|
+
- lib/generators/runger_actions/action/USAGE
|
96
|
+
- lib/generators/runger_actions/action/action_generator.rb
|
97
|
+
- lib/generators/runger_actions/action/templates/action.rb
|
98
|
+
- lib/runger_actions.rb
|
99
|
+
- lib/runger_actions/base.rb
|
100
|
+
- lib/runger_actions/error.rb
|
101
|
+
- lib/runger_actions/result.rb
|
102
|
+
- lib/runger_actions/version.rb
|
103
|
+
- runger_actions.gemspec
|
104
|
+
homepage: https://github.com/davidrunger/runger_actions
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata:
|
108
|
+
rubygems_mfa_required: 'true'
|
109
|
+
homepage_uri: https://github.com/davidrunger/runger_actions
|
110
|
+
source_code_uri: https://github.com/davidrunger/runger_actions
|
111
|
+
changelog_uri: https://github.com/davidrunger/runger_actions/blob/master/CHANGELOG.md
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 3.2.0
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubygems_version: 3.4.4
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Organize (and validate) the business logic of your Rails application.
|
131
|
+
test_files: []
|