interaction 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24abdee95d1dcb71e2f8fcff831c58fbc7eecd56
4
+ data.tar.gz: ce0165495f7ab28fe43bc63055f90816167cc7a4
5
+ SHA512:
6
+ metadata.gz: 53f4b4878a61bcaff9faf77e6a7ae55436d9aab5f31d9982ae8cedd951745eaa8016c769ff60e745fb2c79970573d0964bae22d15631c2ff52f65afa42c859e5
7
+ data.tar.gz: 87e8aea24284006a64b866b9bf5738c6a62ab45458141b526a67346455ae5ddabac091eabd0917fc1fd8ebcf7e18b48f12eb4aa1196497cd9596d78c2516d4d4
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Steve Hodgkiss
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,52 @@
1
+ # Interaction
2
+
3
+ Provides a convention for modelling user interactions as use case classes. A
4
+ use case class represents and is named after something a user does with your
5
+ application `SignUp`, `RequestResetPasswordEmail` etc.
6
+
7
+ Attributes are whitelisted and coerced into an expected type using Virtus. An
8
+ attribute will either be the specified type or nil.
9
+
10
+ Take a look at the [code itself](https://github.com/stevehodgkiss/use_case/blob/master/lib/use_case.rb) for full details of the API provided.
11
+
12
+ ## A simple example
13
+
14
+ ```ruby
15
+ class SignUp
16
+ include Interaction
17
+ include Interaction::ValidationHelpers
18
+ include ActiveModel::Validations
19
+
20
+ # Virtus
21
+ attribute :email, String
22
+ attribute :password, String
23
+
24
+ # ActiveModel validations
25
+ validates :email, :password, presence: true
26
+
27
+ attr_reader :user
28
+
29
+ def perform
30
+ validate!
31
+ create_user
32
+ deliver_welcome_email
33
+ end
34
+
35
+ private
36
+
37
+ def create_user
38
+ @user = User.create(attributes)
39
+ failure! unless @user.persisted?
40
+ end
41
+
42
+ def deliver_welcome_email
43
+ # ...
44
+ end
45
+ end
46
+
47
+ sign_up = SignUp.perform(username: 'john', password: 'j0hn')
48
+ sign_up.success?
49
+ # => true
50
+ sign_up.user
51
+ # => #<User id:...>
52
+ ```
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,26 @@
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 = "interaction"
8
+ spec.version = Interaction::VERSION
9
+ spec.authors = ["Steve Hodgkiss"]
10
+ spec.email = ["steve@hodgkiss.me"]
11
+ spec.summary = %q{Provides a convention for modelling user interactions as use case classes.}
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.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "activemodel"
25
+ spec.add_dependency "virtus", ">= 1.0.4"
26
+ end
@@ -0,0 +1,113 @@
1
+ require "interaction/version"
2
+ require "interaction/params"
3
+ require "interaction/validation_helpers"
4
+
5
+ module Interaction
6
+ # Override Ruby's module inclusion hook to prepend base with our #perform
7
+ # method, extend base with a .perform method, include Params for Virtus and
8
+ # ActiveSupport::Validation.
9
+ #
10
+ # @api private
11
+ def self.included(base)
12
+ base.class_eval do
13
+ prepend Perform
14
+ extend ClassMethods
15
+ include Params
16
+ end
17
+ end
18
+
19
+ module Perform
20
+ # Executes use case logic
21
+ #
22
+ # Use cases must implement this method. Assumes success if failure is not
23
+ # called.
24
+ #
25
+ # @since 0.0.1
26
+ # @api public
27
+ def perform
28
+ catch :halt do
29
+ super.tap do
30
+ success unless result_specified?
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ module ClassMethods
37
+ # Executes and returns the use case
38
+ #
39
+ # A use case object is instantiated with the supplied
40
+ # arguments, perform is called and the object is returned.
41
+ #
42
+ # @param args [*args] Arguments to initialize the use case with
43
+ #
44
+ # @return [Object] returns the use case object
45
+ #
46
+ # @since 0.0.1
47
+ # @api public
48
+ def perform(*args)
49
+ new(*args).tap do |use_case|
50
+ use_case.perform
51
+ end
52
+ end
53
+ end
54
+
55
+ # Indicates if the use case was successful
56
+ #
57
+ # @return [TrueClass, FalseClass]
58
+ #
59
+ # @since 0.0.1
60
+ # @api public
61
+ def success?
62
+ !!@success
63
+ end
64
+
65
+ # Indicates whether the use case failed
66
+ #
67
+ # @return [TrueClass, FalseClass]
68
+ #
69
+ # @since 0.0.1
70
+ # @api public
71
+ def failed?
72
+ !success?
73
+ end
74
+
75
+ private
76
+
77
+ # Mark the use case as successful.
78
+ #
79
+ # @return [TrueClass]
80
+ #
81
+ # @since 0.0.1
82
+ # @api public
83
+ def success
84
+ @success = true
85
+ end
86
+
87
+ # Mark the use case as failed.
88
+ #
89
+ # @since 0.0.1
90
+ # @api public
91
+ def failure
92
+ @success = false
93
+ end
94
+
95
+ # Mark the use case as failed and exits the use case.
96
+ #
97
+ # @since 0.0.1
98
+ # @api public
99
+ def failure!
100
+ failure
101
+ throw :halt
102
+ end
103
+
104
+ # Indicates whether the use case called success or failure
105
+ #
106
+ # @return [TrueClass, FalseClass]
107
+ #
108
+ # @api private
109
+ # @since 0.0.1
110
+ def result_specified?
111
+ defined?(@success)
112
+ end
113
+ end
@@ -0,0 +1,30 @@
1
+ require 'virtus'
2
+
3
+ module Interaction
4
+ # Uses Virtus for whitelisting and type coercion.
5
+ #
6
+ # Virtus is configured in strict mode to ensure input is coerced to either
7
+ # the specified type or nil.
8
+ #
9
+ # @example
10
+ # class SignUpForm
11
+ # include Interaction::Params
12
+ #
13
+ # attribute :name, String
14
+ # end
15
+ #
16
+ # SignUpForm.new(name: 'John Smith').name
17
+ # # => "John Smith"
18
+ #
19
+ # SignUpForm.new(name: ['a']) # => Virtus::CoercionError
20
+ #
21
+ # SignUpForm.new.name
22
+ # # => nil
23
+ module Params
24
+ def self.included(base)
25
+ base.class_eval do
26
+ include Virtus.model(strict: true, required: false)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # Validation helpers intended to be used with
2
+ # ActiveModel::Validations
3
+ module Interaction::ValidationHelpers
4
+ private
5
+
6
+ # Halts execution of the use case if validation fails.
7
+ #
8
+ # @since 0.0.1
9
+ # @api public
10
+ def validate!
11
+ failure unless valid?
12
+ end
13
+
14
+ # Merges errors from another
15
+ # ActiveModel::Validations object with itself.
16
+ #
17
+ # @param object [ActiveModel::Validations]
18
+ #
19
+ # @api public
20
+ def merge_errors(object)
21
+ object.errors.each do |attribute, value|
22
+ errors.add(attribute, value)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Interaction
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Interaction::Params do
4
+ it 'defaults attributes to not required so that nil or the given type is an acceptable value' do
5
+ params = Class.new do
6
+ include Interaction::Params
7
+ attribute :name, String
8
+ end.new
9
+ expect(params.name).to be_nil
10
+ end
11
+
12
+ context 'type coercion' do
13
+ let(:klass) {
14
+ Class.new do
15
+ include Interaction::Params
16
+
17
+ attribute :name, String
18
+ end
19
+ }
20
+
21
+ it 'fails loudly when given an incorrect type' do
22
+ expect {
23
+ klass.new(name: [])
24
+ }.to raise_error(Virtus::CoercionError)
25
+ end
26
+
27
+ it 'does not fail on nil or missing attributes' do
28
+ expect {
29
+ klass.new
30
+ }.not_to raise_error
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'active_model'
3
+
4
+ describe Interaction::ValidationHelpers do
5
+ subject(:use_case) {
6
+ Class.new {
7
+ include Interaction
8
+ include Interaction::ValidationHelpers
9
+ include ActiveModel::Validations
10
+
11
+ def self.model_name
12
+ ActiveModel::Name.new(self, nil, "Test")
13
+ end
14
+
15
+ attr_accessor :name
16
+ validates :name, presence: true
17
+
18
+ def perform
19
+ validate!
20
+ end
21
+
22
+ public :merge_errors
23
+ }.new(params)
24
+ }
25
+ let(:params) { {} }
26
+
27
+ describe '#merge_errors' do
28
+ let(:object) { double(errors: errors) }
29
+ let(:errors) { ActiveModel::Errors.new(Object.new) }
30
+
31
+ before do
32
+ errors.add(:name, 'Test error')
33
+ end
34
+
35
+ it 'merges errors from the given object' do
36
+ use_case.merge_errors(object)
37
+ expect(use_case.errors[:name]).to eq ['Test error']
38
+ end
39
+ end
40
+
41
+ describe '#validate' do
42
+ before { use_case.perform }
43
+
44
+ context 'when validation fails' do
45
+ let(:params) { {} }
46
+
47
+ it { should_not be_success }
48
+ end
49
+
50
+ context 'when validation succeeds' do
51
+ let(:params) { { name: 'Test' } }
52
+
53
+ it { should be_success }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,159 @@
1
+ require 'spec_helper'
2
+
3
+ describe Interaction do
4
+ describe '.perform' do
5
+ let(:use_case_class) do
6
+ Class.new do
7
+ include Interaction
8
+
9
+ def initialize(*args)
10
+ @args = args
11
+ end
12
+
13
+ def perform
14
+ @performed = true
15
+ end
16
+
17
+ def performed?
18
+ @performed
19
+ end
20
+
21
+ attr_reader :args
22
+ end
23
+ end
24
+
25
+ it 'returns the new use case' do
26
+ use_case = use_case_class.perform
27
+ expect(use_case).to be_instance_of(use_case_class)
28
+ end
29
+
30
+ it 'calls #perform' do
31
+ use_case = use_case_class.perform
32
+ expect(use_case).to be_performed
33
+ end
34
+
35
+ it 'passes on args to initialize' do
36
+ use_case = use_case_class.perform(1, 2)
37
+ expect(use_case.args).to eq [1, 2]
38
+ end
39
+
40
+ context "when success or failure isn't indicated" do
41
+ subject(:use_case) { use_case_class.perform }
42
+
43
+ it 'defaults to success' do
44
+ expect(use_case).to be_success
45
+ expect(use_case).to_not be_failed
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#failure' do
51
+ let(:use_case_class) {
52
+ Class.new do
53
+ include Interaction
54
+
55
+ def initialize(*args)
56
+ @args = args
57
+ end
58
+
59
+ def perform
60
+ failure
61
+ @performed = true
62
+ end
63
+
64
+ def performed?
65
+ @performed
66
+ end
67
+ end
68
+ }
69
+ subject(:use_case) { use_case_class.perform }
70
+
71
+ it 'does not halt execution of the use case' do
72
+ expect(use_case).to be_performed
73
+ end
74
+
75
+ it 'marks the use case as failed' do
76
+ expect(use_case).to be_failed
77
+ expect(use_case).to_not be_success
78
+ end
79
+ end
80
+
81
+ describe '#failure!' do
82
+ let(:use_case_class) {
83
+ Class.new do
84
+ include Interaction
85
+
86
+ def initialize(*args)
87
+ @args = args
88
+ end
89
+
90
+ def perform
91
+ failure!
92
+ @performed = true
93
+ end
94
+
95
+ def performed?
96
+ @performed
97
+ end
98
+ end
99
+ }
100
+ subject(:use_case) { use_case_class.perform }
101
+
102
+ it 'halts execution of the use case' do
103
+ expect(use_case).to_not be_performed
104
+ end
105
+
106
+ it 'marks the use case as failed' do
107
+ expect(use_case).to be_failed
108
+ expect(use_case).to_not be_success
109
+ end
110
+ end
111
+
112
+ context 'on exception' do
113
+ let(:my_error) { Class.new(StandardError) }
114
+ let(:use_case_class) {
115
+ Class.new do
116
+ include Interaction
117
+
118
+ def perform
119
+ raise RuntimeError
120
+ end
121
+ end
122
+ }
123
+
124
+ it "marks the use case as failed" do
125
+ use_case = use_case_class.new
126
+ use_case.perform rescue RuntimeError
127
+ expect(use_case).to be_failed
128
+ expect(use_case).to_not be_success
129
+ end
130
+ end
131
+
132
+ describe '#success' do
133
+ let(:use_case_class) {
134
+ Class.new do
135
+ include Interaction
136
+
137
+ def initialize(*args)
138
+ @args = args
139
+ end
140
+
141
+ def perform
142
+ success(*@args)
143
+ @performed = true
144
+ end
145
+
146
+ def performed?
147
+ @performed
148
+ end
149
+ end
150
+ }
151
+ subject(:test) { klass.new(params) }
152
+ let(:params) { {} }
153
+
154
+ it 'marks the use case as success' do
155
+ use_case = use_case_class.perform
156
+ expect(use_case).to be_success
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,90 @@
1
+ require 'interaction'
2
+ # This file was generated by the `rspec --init` command. Conventionally, all
3
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
4
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
5
+ # file to always be loaded, without a need to explicitly require it in any files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need it.
13
+ #
14
+ # The `.rspec` file also contains a few flags that are not defaults but that
15
+ # users commonly want.
16
+ #
17
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
18
+ RSpec.configure do |config|
19
+ # rspec-expectations config goes here. You can use an alternate
20
+ # assertion/expectation library such as wrong or the stdlib/minitest
21
+ # assertions if you prefer.
22
+ config.expect_with :rspec do |expectations|
23
+ # This option will default to `true` in RSpec 4. It makes the `description`
24
+ # and `failure_message` of custom matchers include text for helper methods
25
+ # defined using `chain`, e.g.:
26
+ # be_bigger_than(2).and_smaller_than(4).description
27
+ # # => "be bigger than 2 and smaller than 4"
28
+ # ...rather than:
29
+ # # => "be bigger than 2"
30
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
31
+ end
32
+
33
+ # rspec-mocks config goes here. You can use an alternate test double
34
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
35
+ config.mock_with :rspec do |mocks|
36
+ # Prevents you from mocking or stubbing a method that does not exist on
37
+ # a real object. This is generally recommended, and will default to
38
+ # `true` in RSpec 4.
39
+ mocks.verify_partial_doubles = true
40
+ end
41
+
42
+ # The settings below are suggested to provide a good initial experience
43
+ # with RSpec, but feel free to customize to your heart's content.
44
+ =begin
45
+ # These two settings work together to allow you to limit a spec run
46
+ # to individual examples or groups you care about by tagging them with
47
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
48
+ # get run.
49
+ config.filter_run :focus
50
+ config.run_all_when_everything_filtered = true
51
+
52
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
53
+ # For more details, see:
54
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
55
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
56
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
57
+ config.disable_monkey_patching!
58
+
59
+ # This setting enables warnings. It's recommended, but in some cases may
60
+ # be too noisy due to issues in dependencies.
61
+ config.warnings = true
62
+
63
+ # Many RSpec users commonly either run the entire suite or an individual
64
+ # file, and it's useful to allow more verbose output when running an
65
+ # individual spec file.
66
+ if config.files_to_run.one?
67
+ # Use the documentation formatter for detailed output,
68
+ # unless a formatter has already been configured
69
+ # (e.g. via a command-line flag).
70
+ config.default_formatter = 'doc'
71
+ end
72
+
73
+ # Print the 10 slowest examples and example groups at the
74
+ # end of the spec run, to help surface which specs are running
75
+ # particularly slow.
76
+ config.profile_examples = 10
77
+
78
+ # Run specs in random order to surface order dependencies. If you find an
79
+ # order dependency and want to debug it, you can fix the order by providing
80
+ # the seed, which is printed after each run.
81
+ # --seed 1234
82
+ config.order = :random
83
+
84
+ # Seed global randomization in this process using the `--seed` CLI option.
85
+ # Setting this allows you to use `--seed` to deterministically reproduce
86
+ # test failures related to randomization by passing the same `--seed` value
87
+ # as the one that triggered the failure.
88
+ Kernel.srand config.seed
89
+ =end
90
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: interaction
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Steve Hodgkiss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-05 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.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activemodel
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'
69
+ - !ruby/object:Gem::Dependency
70
+ name: virtus
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.4
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.4
83
+ description: ''
84
+ email:
85
+ - steve@hodgkiss.me
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - interaction.gemspec
97
+ - lib/interaction.rb
98
+ - lib/interaction/params.rb
99
+ - lib/interaction/validation_helpers.rb
100
+ - lib/interaction/version.rb
101
+ - spec/interaction/params_spec.rb
102
+ - spec/interaction/validation_helpers_spec.rb
103
+ - spec/interaction_spec.rb
104
+ - spec/spec_helper.rb
105
+ homepage: ''
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.2.2
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Provides a convention for modelling user interactions as use case classes.
129
+ test_files:
130
+ - spec/interaction/params_spec.rb
131
+ - spec/interaction/validation_helpers_spec.rb
132
+ - spec/interaction_spec.rb
133
+ - spec/spec_helper.rb
134
+ has_rdoc: