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 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
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
19
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in reaction.gemspec
4
+ gemspec
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
@@ -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,15 @@
1
+ module Reaction
2
+ module HasErrors
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ end
9
+
10
+ def errors
11
+ @errors ||= Errors.new
12
+ end
13
+
14
+ end
15
+ 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: []