simple_interaction 0.0.1
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 +14 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +10 -0
- data/bin/rake +16 -0
- data/interaction.gemspec +23 -0
- data/lib/interaction/version.rb +3 -0
- data/lib/interaction.rb +122 -0
- data/test/interaction_test.rb +73 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 902b964d4821ea5d1e0857412061e40a895abb29
|
4
|
+
data.tar.gz: 3e5adefafafd26b0d589f95d7c7ac19254f05aa2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1369a2a7d08fb56833109cb523b117fdc5a3ce9bb6bfd5da6394154fd21f1a95c4556fa7fa7a77523ece4e5327a99ef8d981c92d2bb1d2f239f9b80484d5ba58
|
7
|
+
data.tar.gz: 1886ddbf0a775163c6d2bf838f047515c9cef69819608dd7fa28374f8de19de18ec69013740935f5d6314f829a7470d811f31e00ecf058e48816d19e024887a3
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Jose Boza
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Interaction
|
2
|
+
|
3
|
+
Interactions are meant to keep controllers and models or any other business logic slim (YAY).
|
4
|
+
Keep intention of class clear when using interactions, for example:
|
5
|
+
To create a user, a class should be name Users::Create.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'interaction'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install interaction
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
```
|
26
|
+
class Klass
|
27
|
+
include Interaction
|
28
|
+
|
29
|
+
fail_with 'ErrorClass'
|
30
|
+
requires :param1, :param2
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def run
|
35
|
+
method
|
36
|
+
rescue => e
|
37
|
+
@error = e.message
|
38
|
+
end
|
39
|
+
|
40
|
+
def method
|
41
|
+
param1 / param2
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
interaction = Klass.run(param1: 2, param2: 1)
|
47
|
+
interaction.success? #=> true
|
48
|
+
interaction.error #=> nil
|
49
|
+
interaction.result #=> 2
|
50
|
+
|
51
|
+
Klass.run!(param1: 1, param2: 0) #=> raises Klass::ErrorClass
|
52
|
+
Klass.run!(param1: 1, param2: 2) #=> 2
|
53
|
+
|
54
|
+
```
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
1. Fork it ( https://github.com/[my-github-username]/interaction/fork )
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rake', 'rake')
|
data/interaction.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'interaction/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "simple_interaction"
|
8
|
+
spec.version = Interaction::VERSION
|
9
|
+
spec.authors = ["Jose Boza"]
|
10
|
+
spec.email = ["jaboza@gmail.com"]
|
11
|
+
spec.summary = %q{Keep your code clean with simple interactions}
|
12
|
+
spec.description = %q{}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
data/lib/interaction.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require "interaction/version"
|
2
|
+
|
3
|
+
module Interaction
|
4
|
+
|
5
|
+
# = Interactions
|
6
|
+
#
|
7
|
+
# Interactions are meant to keep controllers and models slim (YAY).
|
8
|
+
# Keep intention of class clear when using interactions
|
9
|
+
# for example to create a user a class should be name Users::Create.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# example of usage:
|
13
|
+
#
|
14
|
+
# class Klass
|
15
|
+
# include Interaction
|
16
|
+
#
|
17
|
+
# requires :param1, :param2
|
18
|
+
#
|
19
|
+
# private
|
20
|
+
#
|
21
|
+
# def run
|
22
|
+
# method
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def method
|
26
|
+
# param1 * param2
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Klass.run(param1: param1, param2: param2)
|
32
|
+
|
33
|
+
class InteractionError< StandardError;end
|
34
|
+
class RequirementsNotMet < InteractionError;end
|
35
|
+
class NotImplemented < InteractionError;end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
|
39
|
+
attr_accessor :accessors
|
40
|
+
|
41
|
+
def accessors
|
42
|
+
@accessors ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def error_class
|
46
|
+
@error_class ||= InteractionError
|
47
|
+
end
|
48
|
+
|
49
|
+
# class method to make sure parameters are required for the interaction to work.
|
50
|
+
def requires(*attrs)
|
51
|
+
set_accessors(attrs)
|
52
|
+
end
|
53
|
+
|
54
|
+
def fail_with(klass)
|
55
|
+
@error_class = self.const_set(klass, Class.new(InteractionError))
|
56
|
+
end
|
57
|
+
|
58
|
+
# checks if requirements are met from the requires params
|
59
|
+
# creates an instance of the interaction
|
60
|
+
# calls run on the instance
|
61
|
+
def run(**options)
|
62
|
+
@options = options
|
63
|
+
fail RequirementsNotMet.new("#{self} requires the following parameters #{accessors}") unless requirements_met?
|
64
|
+
new(@options).__send__(:run)
|
65
|
+
end
|
66
|
+
|
67
|
+
def run!(**options)
|
68
|
+
interaction = run(options)
|
69
|
+
raise error_class.new(interaction.error) unless interaction.success?
|
70
|
+
interaction.result
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def requirements_met?
|
76
|
+
return true if accessors.empty?
|
77
|
+
return false unless @options.kind_of?(Hash)
|
78
|
+
accessors.each do |accessor|
|
79
|
+
break false unless @options.has_key?(accessor)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_accessors(attrs)
|
84
|
+
attr_accessor *attrs
|
85
|
+
accessors.unshift(*attrs)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
module InstanceMethods
|
91
|
+
|
92
|
+
attr_accessor :error, :result, :error_class
|
93
|
+
|
94
|
+
def success?
|
95
|
+
error.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# initializes instance and sets the instance variable for each attr_accessor from the required parameters
|
101
|
+
def initialize(**opts)
|
102
|
+
|
103
|
+
opts.select { |option, _| self.class.accessors.include?(option) }.each do |accessor, value|
|
104
|
+
__send__("#{accessor}=", value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# run method should be overwritten on every class where interaction is included
|
109
|
+
def run
|
110
|
+
fail NotImplemented.new("`run` instance method must be implemented in class #{self.class}") unless defined?(super)
|
111
|
+
interaction_run = super
|
112
|
+
@result = interaction_run if success?
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.included(receiver)
|
119
|
+
receiver.extend ClassMethods
|
120
|
+
receiver.send :prepend, InstanceMethods
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'interaction'
|
3
|
+
|
4
|
+
class Interactor
|
5
|
+
include Interaction
|
6
|
+
|
7
|
+
fail_with 'InteractorExp'
|
8
|
+
|
9
|
+
requires :param
|
10
|
+
|
11
|
+
def run
|
12
|
+
@error = "only strings please" if param =~ /\d{1,}/
|
13
|
+
"This is the result for #{param}"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class InteractorNotImplemented
|
19
|
+
include Interaction
|
20
|
+
end
|
21
|
+
|
22
|
+
module Interaction
|
23
|
+
class InteractionTest < ::Minitest::Test
|
24
|
+
|
25
|
+
def test_private_run
|
26
|
+
assert Interactor.private_method_defined?(:run), 'instance method run should be private'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_error_class
|
30
|
+
assert_equal Interactor::InteractorExp, Interactor.error_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_error_class_not_defined
|
34
|
+
assert_equal Interaction::InteractionError, InteractorNotImplemented.error_class
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_require_params
|
38
|
+
assert_raises RequirementsNotMet do
|
39
|
+
Interactor.run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_result
|
44
|
+
assert_equal "This is the result for awesome interaction", Interactor.run(param: 'awesome interaction').result
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_success
|
48
|
+
assert Interactor.run(param: 'awesome interaction').success?, 'Interactor didn\'t finish successfuly'
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_run_with_bang
|
52
|
+
assert_equal "This is the result for awesome interaction", Interactor.run!(param: 'awesome interaction')
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_error
|
56
|
+
interaction = Interactor.run(param: '1')
|
57
|
+
refute interaction.success?, 'Interactor didn\'t finish with an error'
|
58
|
+
assert_match interaction.error, "only strings please"
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_error_with_bang
|
62
|
+
exception = assert_raises(Interactor::InteractorExp) { Interactor.run!(param: '1') }
|
63
|
+
assert_equal "only strings please", exception.message
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_not_implemented
|
67
|
+
assert_raises(Interaction::NotImplemented) { InteractorNotImplemented.run(param: '1') }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_interaction
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jose Boza
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: ''
|
42
|
+
email:
|
43
|
+
- jaboza@gmail.com
|
44
|
+
executables:
|
45
|
+
- rake
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- bin/rake
|
55
|
+
- interaction.gemspec
|
56
|
+
- lib/interaction.rb
|
57
|
+
- lib/interaction/version.rb
|
58
|
+
- test/interaction_test.rb
|
59
|
+
homepage: ''
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.2.2
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Keep your code clean with simple interactions
|
83
|
+
test_files:
|
84
|
+
- test/interaction_test.rb
|