reaction 0.0.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/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/lib/reaction/action.rb +55 -0
- data/lib/reaction/doc.rb +17 -0
- data/lib/reaction/each_validator.rb +43 -0
- data/lib/reaction/errors.rb +45 -0
- data/lib/reaction/has_docs.rb +18 -0
- data/lib/reaction/has_errors.rb +15 -0
- data/lib/reaction/has_metas.rb +23 -0
- data/lib/reaction/has_params.rb +49 -0
- data/lib/reaction/has_types.rb +28 -0
- data/lib/reaction/has_validators.rb +33 -0
- data/lib/reaction/type.rb +40 -0
- data/lib/reaction/types/raw_type.rb +16 -0
- data/lib/reaction.rb +14 -0
- data/reaction.gemspec +18 -0
- metadata +60 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 70ffb42ccf83ba294bfb07d8887055c9a2343d2e
|
|
4
|
+
data.tar.gz: 44a1abae9c843a15bbe634c28ab867216b1042f4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cc74f3443a4b55a2828c03ce89b971f7022320f8cbb994b5e8c099ee4ebdb48d24abd2ab8e78e9a76049d2bd257a4ec45504ba963c590238a7ddbcb6e8b9010d
|
|
7
|
+
data.tar.gz: be02f4c83dbf04a96762b3d009942542ff477e0c21962d8a5d5b475598939293d8db2db83a48fc72894ae26a6b2f108c12b1f3b5121dc2695111ea3c81b8922f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2016 Jonathan Calhoun
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
class Action
|
|
3
|
+
include HasErrors
|
|
4
|
+
include HasParams
|
|
5
|
+
|
|
6
|
+
# meta isn't used by default, but it is supported for use cases
|
|
7
|
+
# where you need to attach metadata to parameters, such as
|
|
8
|
+
# who or what set the attribute. For example, Paid currently
|
|
9
|
+
# has a flow like:
|
|
10
|
+
#
|
|
11
|
+
# action = Action.new(request.params, via: :request)
|
|
12
|
+
# action.set_params(account: api_key.account, via: :api_key)
|
|
13
|
+
#
|
|
14
|
+
# Which allows us to use a validator to define who can set
|
|
15
|
+
# various attributes. Specifically, we limit certain attributes
|
|
16
|
+
# from being set by the request so end users can't set params
|
|
17
|
+
# that we don't expect them to set.
|
|
18
|
+
#
|
|
19
|
+
def initialize(params = {}, meta = {})
|
|
20
|
+
set_params(params, meta)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def invoke
|
|
24
|
+
validate!
|
|
25
|
+
ret = perform
|
|
26
|
+
ensure
|
|
27
|
+
cleanup
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def perform
|
|
31
|
+
# Implement this for your action
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def validate!
|
|
35
|
+
self.class.types.each do |name, type|
|
|
36
|
+
type.validate_each(self, name, raw_param(name))
|
|
37
|
+
end
|
|
38
|
+
self.class.validators.each do |name, validator|
|
|
39
|
+
validator.validate_each(self, name, raw_param(name))
|
|
40
|
+
end
|
|
41
|
+
if errors.any?
|
|
42
|
+
raise ArgumentError.new("Validations failed: #{errors.full_messages.join(',')}")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def cleanup
|
|
47
|
+
self.class.types.each do |name, type|
|
|
48
|
+
type.cleanup
|
|
49
|
+
end
|
|
50
|
+
self.class.validators.each do |name, validator|
|
|
51
|
+
validator.cleanup
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/reaction/doc.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# This class serves no real purpose in this gem, but is here so that
|
|
2
|
+
# developers can use it to create more dynamic documentation by
|
|
3
|
+
# documenting attributes used for actions directly in the actions,
|
|
4
|
+
# and then access these when generating their actual documenation.
|
|
5
|
+
#
|
|
6
|
+
module Reaction
|
|
7
|
+
class Doc
|
|
8
|
+
attr_reader :name, :message, :options
|
|
9
|
+
|
|
10
|
+
def initialize(name, message, options = {})
|
|
11
|
+
@name = name.to_sym
|
|
12
|
+
@message = message
|
|
13
|
+
@options = options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
class EachValidator
|
|
3
|
+
attr_reader :options
|
|
4
|
+
|
|
5
|
+
def initialize(options = {})
|
|
6
|
+
@options = options
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# If you need to validate a parameter outside of the basic
|
|
10
|
+
# type then validators are your best bet. They are generally
|
|
11
|
+
# very similar to Rails' EachValidator. You provide a
|
|
12
|
+
# validate_each method that takes in a record, attribute, and
|
|
13
|
+
# value and then if the attribute isn't valid adds an error
|
|
14
|
+
# to record.errors. You can also access the data provided
|
|
15
|
+
# for the validator via the +options+ method.
|
|
16
|
+
#
|
|
17
|
+
# Example validate_each method for a RequiredValidator which
|
|
18
|
+
# would be used like:
|
|
19
|
+
#
|
|
20
|
+
# param :cat, required: true
|
|
21
|
+
# param :dog, required: false
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
# def validate_each(record, attribute, value)
|
|
25
|
+
# if options && value.nil?
|
|
26
|
+
# record.errors.add(attribute, 'is required.')
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
def validate_each(record, attribute, value)
|
|
31
|
+
raise NotImplementedError.new('Subclasses must implement a validate_each(record, attribute, value) method')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Cleanup is provided in case you need to create files that
|
|
35
|
+
# require cleanup after the action has been performed. For
|
|
36
|
+
# example, Paid creates Tempfiles with some types and uses
|
|
37
|
+
# the cleanup phase to ensure these files get closed up
|
|
38
|
+
# properly.
|
|
39
|
+
#
|
|
40
|
+
def cleanup
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
class Errors
|
|
3
|
+
|
|
4
|
+
attr_accessor :messages
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@messages = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def clear
|
|
11
|
+
messages.clear
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def include?(key)
|
|
15
|
+
!messages[key].nil?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get(key)
|
|
19
|
+
messages[key]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add(key, message)
|
|
23
|
+
messages[key] ||= []
|
|
24
|
+
messages[key] << message
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def any?
|
|
28
|
+
messages.any?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def each
|
|
32
|
+
messages
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def full_messages
|
|
36
|
+
ret = []
|
|
37
|
+
messages.each do |key, values|
|
|
38
|
+
values.each do |value|
|
|
39
|
+
ret << "#{key}: #{value}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
ret
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
module HasDocs
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def doc(name, message, options = {})
|
|
9
|
+
docs[name.to_sym] = Doc.new(name, message, options)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def docs
|
|
13
|
+
@docs ||= {}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
module HasMetas
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def meta(name)
|
|
11
|
+
metas[name.to_sym]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def metas
|
|
15
|
+
@metas ||= {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def set_meta(name, meta)
|
|
19
|
+
metas[name.to_sym] = meta
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
module HasParams
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.include HasDocs
|
|
5
|
+
base.include HasMetas
|
|
6
|
+
base.include HasTypes
|
|
7
|
+
base.include HasValidators
|
|
8
|
+
base.extend ClassMethods
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
def param(name, options = {})
|
|
13
|
+
set_type(name, options.delete(:type))
|
|
14
|
+
set_validators(name, options)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def param(name)
|
|
19
|
+
typed_params[name.to_sym] ||= begin
|
|
20
|
+
type = self.class.types[name.to_sym]
|
|
21
|
+
type ? type.convert(raw_param(name)) : raw_param(name)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def params
|
|
26
|
+
@params ||= {}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def typed_params
|
|
30
|
+
@typed_params ||= {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_param(name, value, meta = {})
|
|
34
|
+
set_meta(name, meta)
|
|
35
|
+
params[name.to_sym] = value
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def set_params(params = {}, meta = {})
|
|
39
|
+
params.each do |name, value|
|
|
40
|
+
set_param(name, value, meta)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def raw_param(name)
|
|
45
|
+
params[name.to_sym]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
module HasTypes
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def types
|
|
9
|
+
@types ||= {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def set_type(name, type)
|
|
13
|
+
type ||= Type
|
|
14
|
+
klass = class_for_type(type)
|
|
15
|
+
types[name.to_sym] = klass.new(name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def class_for_type(type)
|
|
19
|
+
return type if type.is_a?(Class)
|
|
20
|
+
name = type.to_s.split('_').map(&:capitalize).join
|
|
21
|
+
const_get("#{name}Type")
|
|
22
|
+
rescue NameError
|
|
23
|
+
raise ArgumentError.new("Unknown param type: #{type}")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
module HasValidators
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def validators
|
|
9
|
+
@validators ||= {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def set_validator(name, validator, options = {})
|
|
13
|
+
klass = class_for_validator(validator)
|
|
14
|
+
validators[name.to_sym] = klass.new(options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_validators(name, validators = {})
|
|
18
|
+
validators.each do |validator, options|
|
|
19
|
+
set_validator(name, validator, options)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def class_for_validator(validator)
|
|
24
|
+
return validator if validator.is_a?(Class)
|
|
25
|
+
name = validator.to_s.split('_').map(&:capitalize).join
|
|
26
|
+
const_get("#{name}Validator")
|
|
27
|
+
rescue NameError
|
|
28
|
+
raise ArgumentError.new("Unknown param validator: #{validator}")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
class Type
|
|
3
|
+
attr_reader :name
|
|
4
|
+
|
|
5
|
+
def initialize(name)
|
|
6
|
+
@name = name.to_sym
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# If you need to validate based on type you can. These
|
|
10
|
+
# work identically to the validators, except type validations
|
|
11
|
+
# are always called before other validators, and the +options+
|
|
12
|
+
# hash isn't available. If you have a particularly good
|
|
13
|
+
# use case for passing in options to a Type reach out; It
|
|
14
|
+
# should be pretty easy to add in, we just haven't had a
|
|
15
|
+
# need for it yet.
|
|
16
|
+
#
|
|
17
|
+
def validate_each(record, attribute, value)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Convert is used to transform a value into whatever
|
|
21
|
+
# format you expect it to be. For example, you might
|
|
22
|
+
# have a convert method that casts a string into an
|
|
23
|
+
# integer, or one that takes in various date formats
|
|
24
|
+
# and converts them to a DateTime prior to the param
|
|
25
|
+
# being used in the action.
|
|
26
|
+
#
|
|
27
|
+
def convert(value)
|
|
28
|
+
value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Cleanup is provided in case you need to create files that
|
|
32
|
+
# require cleanup after the action has been performed. For
|
|
33
|
+
# example, Paid creates Tempfiles with some types and uses
|
|
34
|
+
# the cleanup phase to ensure these files get closed up
|
|
35
|
+
# properly.
|
|
36
|
+
#
|
|
37
|
+
def cleanup
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This is the default type for any param. It doesn't do any
|
|
2
|
+
# validations and simply returns the value as provided.
|
|
3
|
+
#
|
|
4
|
+
module Reaction
|
|
5
|
+
class RawType < Type
|
|
6
|
+
def validate_each(record, attribute, value)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def convert(value)
|
|
10
|
+
value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def cleanup
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/reaction.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Reaction
|
|
2
|
+
autoload :Action, 'reaction/action'
|
|
3
|
+
autoload :Doc, 'reaction/doc'
|
|
4
|
+
autoload :EachValidator, 'reaction/each_validator'
|
|
5
|
+
autoload :Errors, 'reaction/errors'
|
|
6
|
+
autoload :HasDocs, 'reaction/has_docs'
|
|
7
|
+
autoload :HasErrors, 'reaction/has_errors'
|
|
8
|
+
autoload :HasMetas, 'reaction/has_metas'
|
|
9
|
+
autoload :HasParams, 'reaction/has_params'
|
|
10
|
+
autoload :HasTypes, 'reaction/has_types'
|
|
11
|
+
autoload :HasValidators, 'reaction/has_validators'
|
|
12
|
+
autoload :RawType, 'reaction/types/raw_type'
|
|
13
|
+
autoload :Type, 'reaction/type'
|
|
14
|
+
end
|
data/reaction.gemspec
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |gem|
|
|
6
|
+
gem.name = 'reaction'
|
|
7
|
+
gem.version = '0.0.0'
|
|
8
|
+
gem.authors = ["Jonathan Calhoun"]
|
|
9
|
+
gem.email = ["joncalhoun@gmail.com"]
|
|
10
|
+
gem.description = 'Reaction is a library to help build reusable actions for Rails controllers.'
|
|
11
|
+
gem.summary = 'Reaction is a library to help build reusable actions for Rails controllers.'
|
|
12
|
+
gem.homepage = 'https://github.com/joncalhoun/reaction'
|
|
13
|
+
|
|
14
|
+
gem.files = `git ls-files`.split($/)
|
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
gem.require_paths = ["lib"]
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: reaction
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jonathan Calhoun
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-02-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Reaction is a library to help build reusable actions for Rails controllers.
|
|
14
|
+
email:
|
|
15
|
+
- joncalhoun@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- ".gitignore"
|
|
21
|
+
- Gemfile
|
|
22
|
+
- LICENSE.txt
|
|
23
|
+
- lib/reaction.rb
|
|
24
|
+
- lib/reaction/action.rb
|
|
25
|
+
- lib/reaction/doc.rb
|
|
26
|
+
- lib/reaction/each_validator.rb
|
|
27
|
+
- lib/reaction/errors.rb
|
|
28
|
+
- lib/reaction/has_docs.rb
|
|
29
|
+
- lib/reaction/has_errors.rb
|
|
30
|
+
- lib/reaction/has_metas.rb
|
|
31
|
+
- lib/reaction/has_params.rb
|
|
32
|
+
- lib/reaction/has_types.rb
|
|
33
|
+
- lib/reaction/has_validators.rb
|
|
34
|
+
- lib/reaction/type.rb
|
|
35
|
+
- lib/reaction/types/raw_type.rb
|
|
36
|
+
- reaction.gemspec
|
|
37
|
+
homepage: https://github.com/joncalhoun/reaction
|
|
38
|
+
licenses: []
|
|
39
|
+
metadata: {}
|
|
40
|
+
post_install_message:
|
|
41
|
+
rdoc_options: []
|
|
42
|
+
require_paths:
|
|
43
|
+
- lib
|
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
requirements: []
|
|
55
|
+
rubyforge_project:
|
|
56
|
+
rubygems_version: 2.4.5
|
|
57
|
+
signing_key:
|
|
58
|
+
specification_version: 4
|
|
59
|
+
summary: Reaction is a library to help build reusable actions for Rails controllers.
|
|
60
|
+
test_files: []
|