ruby-mutant 1.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
+ SHA256:
3
+ metadata.gz: 51e7408e70faf6d2d947d56810cb097eb612234a92809ae92d1ba190cff3b976
4
+ data.tar.gz: d99ff9d4b8045ef89dc965081e872829cf08b8ceb313c04d3f48703ca54e1369
5
+ SHA512:
6
+ metadata.gz: 5fdf4681e19da56d8e37edb0dc1289804eb98731193685777914831f7f94582491eab9f2ce788cd488c5495769806c5172a2da274da19bd1b0dbd10f17fdd74b
7
+ data.tar.gz: 19113031cd96afcc38351c4d6b8818a43ba712e100df8475bb11e9bdda21e32da0a247453bb35fef2dae2f63dc34809948a155a207323edd8bfbf6a14cb11d6e
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+ A clear and concise description of what the bug is.
12
+
13
+ **To Reproduce**
14
+ Steps to reproduce the behavior:
15
+
16
+
17
+ **Expected behavior**
18
+ A clear and concise description of what you expected to happen.
19
+
20
+
21
+
22
+ **Additional context**
23
+ Add any other context about the problem here.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Additional context**
20
+ Add any other context or screenshots about the feature request here.
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.idea
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ .byebug_history
data/.rakeTasks ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake" /></Settings>
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.6
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
1
+
2
+ ## How to contribute to RubyMutant
3
+ ---
4
+
5
+ Did you find a bug?
6
+ - Ensure the bug was not already reported by searching on Github under [issues](https://github.com/coreyjs/ruby-mutant/issues).
7
+ - If you are unable to find any issue that is the same or address your problem, feel free to open a new bug report issue. A clear and concise title and description of the bug and as much information possible on reproducible steps would greatly ensure the squashing of said bug.
8
+
9
+
10
+ **Did you create a patch that fixes a bug?**
11
+ - Open a new PR with the code fix
12
+ - Ensure your PR description is clear and concise and describes the problem and the solution. Include the issue # as well.
13
+ - Make sure your patch has the appropriate test coverage to confirm the fix.
14
+ - Once in review, a maintainer will review the PR and provide any needed feedback and guidance to help get the PR merged in.
15
+
16
+
17
+ **Did you want to add a new feature or enhancement?**
18
+ - Create a feature request using the "Feature Request" issue template, [here](https://github.com/coreyjs/ruby-mutant/issues/new?assignees=&labels=&template=feature_request.md&title=)
19
+ - Be clear about the feature you want to add, the problem it is looking to solve or the idea/intent behind the feature.
20
+ - If you plan to build the feature yourself, tag the issue with the label `work in progress` and assign yourself as an `Assignee` (or a maintainer can if permissions dont allow).
21
+ - For branch naming conventions when dealing with features, please prefix the branch name with`feature/` such as `feature/this-adds-async-support`
22
+ - Once ready for review, open a PR with the base branch being `master`. Once all builds are complete and passing, a maintainer will your with you to finalize any code changes that may be necessary.
23
+
24
+
25
+ Thanks everyone for their interest in this project! This is meant to be a learning expiernce for everyone, to learn how to contribute and work in open source. I encourage you to pitch in and let your creativity drive you. ❤️❤️❤️
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in ruby-mutant.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-mutant (0.0.4)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (13.0.1)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.0)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.2)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.16)
30
+ rake (~> 13.0)
31
+ rspec (~> 3.0)
32
+ ruby-mutant!
33
+
34
+ BUNDLED WITH
35
+ 1.17.3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Corey Schaf
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Ruby Mutant
2
+ [![Build Status](https://travis-ci.org/coreyjs/ruby-mutant.svg?branch=master)](https://travis-ci.org/coreyjs/ruby-mutant)
3
+
4
+
5
+ ## Installation
6
+
7
+
8
+ ```ruby
9
+ gem 'ruby-mutant', git: 'https://github.com/coreyjs/ruby-mutant'
10
+ ```
11
+
12
+ ---
13
+ ## Usage
14
+
15
+ Ruby Mutant is a lightweight mutations library to help you encapsulate your business logic into decoupled, testable mutations. With Ruby Mutant you can easily add executable code with validation, helping you decouple important logic from your application.
16
+
17
+ To create a mutation from a ruby object, include the ruby module `require "mutatant"`
18
+
19
+
20
+
21
+ ```ruby
22
+ require "mutant"
23
+
24
+ class RecipeCreatedMutation
25
+ include Mutant
26
+
27
+ required_attr :recipe
28
+
29
+ #Define custom validators for our attributes
30
+ def validate_name?
31
+ true
32
+ end
33
+
34
+ # Required, this will execute our new mutation.
35
+ def execute(args)
36
+ # here, recipe is passe into out Class.run(recipe=Recipe.new) method
37
+ if recipe.difficulty == 'godlike'
38
+ recipe_service.send_alert_new_super_recipe_confirmation()
39
+ end
40
+ end
41
+ end
42
+ ```
43
+
44
+ ---
45
+ To run a mutation definition:
46
+ ```ruby
47
+ # run() excepts any number of parameters that you want to pass into your mutation
48
+ output = RecipeCreatedMutation.run(recipe: Recipe.new, obj2: obj2, ....)
49
+ ```
50
+
51
+ Every mutation execution will return an `output` object. This object contains information on the
52
+ mutation execution, and errors occurred or any metadata that's needed to be returned from the mutation,
53
+ in the form of a hash.
54
+
55
+ Any meta data that needs to be returned can be added to the output object using the
56
+ helper method inside your mutation:
57
+
58
+ ```ruby
59
+ class RecipeCreatedMutation
60
+ include Mutant
61
+ ...
62
+ def execute(args)
63
+ output.add_meta(:test, 'value')
64
+ end
65
+
66
+ ...
67
+
68
+ output = RecipeCreatedMutation.run()
69
+ output.meta[:test] # >> 'value'
70
+
71
+ ```
72
+
73
+ ```ruby
74
+ output = RecipeCreatedMutation.run(obj: obj1)
75
+ output.success? # >> true
76
+ output.errors # >> [err1, err1, ...]
77
+ output.meta # > {:my => 'value', :other => 'value1'}
78
+ ```
79
+
80
+ ---
81
+ ## How to use this library
82
+
83
+ ### Rails:
84
+ We could define a folder structure such as this, for our rails Recipe web app:
85
+ ```
86
+ /lib/use_cases/recipes/recipe_created_mutation.rb
87
+ /lib/use_cases/user/new_user_signed_up_mutation.rb
88
+ ```
89
+
90
+ `recipe_created_mutation.rb`
91
+ ```ruby
92
+ require 'mutant'
93
+
94
+ module UseCases::Recipes
95
+ class RecipeCreatedMutation
96
+ include Mutant
97
+
98
+ required_attr :recipe
99
+
100
+ def execute(args)
101
+ if recipe.name.blank?
102
+ puts 'whoops this recipe is bad'
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ ```
109
+
110
+ And in a controller, we can execute the mutation like so:
111
+
112
+ ```ruby
113
+ class RecipesController < ApplicationController
114
+ include UseCases::Recipes
115
+
116
+
117
+ def create
118
+ @recipe = Recipe.new(recipe_params)
119
+
120
+ output = RecipeCreatedMutation.run(recipe: @recipe)
121
+
122
+ if output.success?
123
+ puts 'everything went super duper good'
124
+ end
125
+ end
126
+
127
+ ...
128
+ end
129
+ ```
130
+
131
+
132
+ ---
133
+
134
+
135
+ ## Contributing
136
+
137
+ Bug reports and pull requests are welcome on GitHub at https://github.com/coreyjs/ruby-mutant. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
138
+
139
+ For more information on contributing, here: [How To Contribute](https://github.com/coreyjs/ruby-mutant/blob/master/CONTRIBUTING.md)
140
+
141
+ ## License
142
+
143
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
144
+
145
+
146
+ ## Special thanks to the inspiration for this library!
147
+
148
+ https://github.com/cypriss/mutations
149
+
150
+ https://github.com/omarish/mutations
151
+
152
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ruby-mutant"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/mutant.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "ruby-mutant/version"
2
+ require "ruby-mutant/base"
3
+
4
+ module Mutant
5
+ end
@@ -0,0 +1,156 @@
1
+ require 'ruby-mutant/exceptions/mutation_validation_exception'
2
+ require 'ruby-mutant/exceptions/mutation_setup_exception'
3
+ require 'ruby-mutant/exceptions/mutation_missing_required_var_exception'
4
+ require 'ruby-mutant/output'
5
+ require "bundler/setup"
6
+
7
+
8
+ module Mutant
9
+ attr_accessor :output
10
+
11
+ def self.included(klass)
12
+ klass.extend(ClassMethods)
13
+ end
14
+
15
+ module ClassMethods
16
+ def required_attr(*attrs)
17
+ puts 'Mutant::required_attr'
18
+ # This defines a method called required_attr that will
19
+ # return an array of symbols for all the properties of the
20
+ # mutation that we should have defined.
21
+ define_method(:required_attr) { attrs ||= [] }
22
+ end
23
+
24
+ # The entry point, main method that will be execute any mutation logic
25
+ #
26
+ # == Parameters:
27
+ # args::
28
+ # A hash of inputs suppplied when the user runs the mutation.
29
+ # i.e. MyMutation.run(name: 'jon', house: 'stark')
30
+ #
31
+ # == Returns:
32
+ # An instance of `Mutant::Output`. This object defines all
33
+ # errors, metadata and success definition of the mutation
34
+ def run(args = {})
35
+ unless args.has_key?(:raise_on_error)
36
+ args[:raise_on_error] = true
37
+ end
38
+ args[:raise_on_error].freeze
39
+
40
+ puts 'Mutant::self.run(*args) '
41
+ obj = new(args)
42
+
43
+ # Ensure the mutation has the correct method
44
+ unless obj.respond_to?(:execute)
45
+ raise MutationSetupException.new(msg='Missing execute method')
46
+ end
47
+
48
+ # 1. We want to run the validators first, then determine if we should continue
49
+ errs = obj.send(:validate)
50
+ obj.output.errors = obj.output.errors + errs
51
+ if errs.length > 0
52
+ if args[:raise_on_error]
53
+ raise MutationSetupException.new(msg='Validation failed')
54
+ end
55
+ end
56
+
57
+ # 2. Check to see the mutation has the corresponding inst vars
58
+ args.each do |k, val|
59
+ puts "Mutant::var check '#{k}', responds? #{obj.respond_to? k.to_sym}"
60
+
61
+ # First make sure this mutation obj has the correct vars,
62
+ # if not, then proceeed to create them
63
+ unless obj.respond_to? k.to_sym
64
+ # create the attr_accessor for the missing vars
65
+ obj.class.send(:define_method, "#{k}=".to_sym) do |value|
66
+ instance_variable_set("@" + k.to_s, value)
67
+ end
68
+ obj.class.send(:define_method, k.to_sym) do
69
+ instance_variable_get("@" + k.to_s)
70
+ end
71
+ end
72
+
73
+ # 3. Propagate the values from the mutation props to the class
74
+ obj.send("#{k}=".to_sym, val)
75
+ end
76
+
77
+ # 3 If this instance defines :required_attr
78
+ if obj.respond_to? :required_attr
79
+ required_attr_errors = obj.send(:check_required_attrs)
80
+ unless required_attr_errors.length == 0
81
+ # We need to handle any errors we get back from our
82
+ # required_attr validator
83
+ obj.output.errors += required_attr_errors
84
+ if args[:raise_on_error]
85
+ raise required_attr_errors[0]
86
+ end
87
+ end
88
+ end
89
+
90
+ # 4. Run execute method to run mutation logic
91
+ obj.execute(args)
92
+ # Return out Output obj, with all meta data regarding the ran mutation
93
+ obj.output
94
+ end
95
+ end
96
+
97
+ def initialize(*args)
98
+ @output = Output.new
99
+ end
100
+
101
+ private
102
+
103
+ # This will run all ou validation functions on our mutation class.
104
+ # This will return an array of MutationValidationException, to the class method, run()
105
+ #
106
+ # == Parameters:
107
+ #
108
+ # == Returns:
109
+ # errors. An array of errors representing all validation methods that have failed.
110
+ # (defaults to `[]`)
111
+ def validate
112
+ errors = []
113
+ self.public_methods.each do |m|
114
+ if m.to_s.start_with?('validate_') && m.to_s.end_with?('?')
115
+ # execute validation method
116
+ res = self.send(m)
117
+
118
+ # unless the response is truthy
119
+ unless res
120
+ errors << MutationValidationException.new(msg='Validator has returned false', validator=m)
121
+ end
122
+ end
123
+ end
124
+ errors
125
+ end
126
+
127
+ # Checks to see if any `required_attr` has been set, if so check to see if each one
128
+ # is defined in either the .run() definition or the mutation's `attr_accesor`.
129
+ # TODO need to also check that these required attributes have values
130
+ #
131
+ # == Parameters:
132
+ #
133
+ # == Returns:
134
+ # An array of errors, of type `MutationMissingRequiredVarException`, for each
135
+ # missing required attribute.
136
+ def check_required_attrs
137
+ # In this we need to compare what we define in
138
+ # required_attr(*attrs) against what we have defined in
139
+ # the mutation vs what we pass into the run() definition
140
+ errors = []
141
+ puts 'Mutant::check_required_attrs'
142
+ self.required_attr.each do |attr|
143
+ if !self.respond_to?(attr)
144
+ # Our attribute is not defined on our mutation class
145
+ # So we will build the error to return to the run()
146
+ # method, which can determine how we proceed
147
+ err = MutationMissingRequiredVarException.new(
148
+ msg="A property that is marked as required is not defined on the mutation: #{attr}",
149
+ prop=attr)
150
+ errors << err
151
+ end
152
+ end
153
+ errors
154
+ end
155
+
156
+ end
@@ -0,0 +1,7 @@
1
+ class MutationMissingRequiredVarException < StandardError
2
+ attr_reader :prop
3
+ def initialize(msg='MutationMissingRequiredVarException', prop=nil)
4
+ @prop = prop
5
+ super("#{msg} - #{prop}")
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class MutationSetupException < StandardError
2
+ def initialize(msg='MutationSetupException')
3
+ super(msg)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class MutationValidationException < StandardError
2
+ def initialize(msg='MutationValidationError', validator=nil)
3
+ super("#{msg} - #{validator}")
4
+ end
5
+ end
@@ -0,0 +1,60 @@
1
+ module Mutant
2
+ class Output
3
+
4
+ # Allows to reading the status of the executed mutation
5
+ attr_reader :success
6
+
7
+ # @return [Hash] the hash of metadata the user wants returned from the mutation execution
8
+ attr_accessor :meta
9
+
10
+ # @return [Array] The get/set for the mutations errors that have been thrown
11
+ attr_accessor :errors
12
+
13
+ # Output constructor
14
+ #
15
+ # == Parameters:
16
+ # success::
17
+ # The successful state of the mutation that owns this object. (defaults to `true`)
18
+ # errors::
19
+ # An array of errors that can be packaged and wrapped in this object to be
20
+ # `returned` from the mutation's `execute` method. (defaults to `[]`)
21
+ # meta::
22
+ # A hash map that can be used to set any information that needs to be returned
23
+ # from the mutation to the calling code. (defaults to `{}`)
24
+ #
25
+ def initialize(success=true, errors=[], meta={})
26
+ @success = success
27
+ @errors = errors
28
+ @meta = meta
29
+ end
30
+
31
+ # Adds meta data to the @meta hash
32
+ # (will overwrite existing value)
33
+ #
34
+ # == Parameters:
35
+ # key::
36
+ # A symbol that will be used to store the value in the hash
37
+ #
38
+ # value::
39
+ # Any value that you wish to store indexed by the `key` param.
40
+ # This can be used if you need to return data from the mutation's `execute` method
41
+ #
42
+ # == Returns:
43
+ # Nothing useful
44
+ def add_meta(key, value)
45
+ @meta[key] = value
46
+ end
47
+
48
+ # Helper method to determine successfulnes of the mutation that has ran. A successful
49
+ # mutation execution is defined by having an error count of 0.
50
+ # TODO: This needs to be handled better, more smart about what success means
51
+ #
52
+ # == Parameters:
53
+ #
54
+ # == Returns:
55
+ # A boolean that represents the status of the just execute mutation
56
+ def success?
57
+ @success
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module Mutant
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,30 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "ruby-mutant/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ruby-mutant"
8
+ spec.version = Mutant::VERSION
9
+ spec.authors = ["Corey Schaf"]
10
+ spec.email = ["cschaf@gmail.com"]
11
+
12
+ spec.summary = %q{Clean up your code by encapsulating business logic in mutations!}
13
+ spec.description = %q{Object mutations that encapsulate business logic.
14
+ RubyMutant makes it simple to add complex logic to objects, in with automatic validation and execution.}
15
+ spec.homepage = "https://github.com/coreyjs/ruby-mutant"
16
+ spec.license = "MIT"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.16"
28
+ spec.add_development_dependency "rake", "~> 13.0"
29
+ spec.add_development_dependency "rspec", "~> 3.0"
30
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-mutant
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Corey Schaf
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-05-01 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.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.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: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: |-
56
+ Object mutations that encapsulate business logic.
57
+ RubyMutant makes it simple to add complex logic to objects, in with automatic validation and execution.
58
+ email:
59
+ - cschaf@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
65
+ - ".github/ISSUE_TEMPLATE/feature_request.md"
66
+ - ".gitignore"
67
+ - ".rakeTasks"
68
+ - ".rspec"
69
+ - ".travis.yml"
70
+ - CODE_OF_CONDUCT.md
71
+ - CONTRIBUTING.md
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - LICENSE
75
+ - LICENSE.txt
76
+ - README.md
77
+ - Rakefile
78
+ - bin/console
79
+ - bin/setup
80
+ - lib/mutant.rb
81
+ - lib/ruby-mutant/base.rb
82
+ - lib/ruby-mutant/exceptions/mutation_missing_required_var_exception.rb
83
+ - lib/ruby-mutant/exceptions/mutation_setup_exception.rb
84
+ - lib/ruby-mutant/exceptions/mutation_validation_exception.rb
85
+ - lib/ruby-mutant/output.rb
86
+ - lib/ruby-mutant/version.rb
87
+ - ruby-mutant.gemspec
88
+ homepage: https://github.com/coreyjs/ruby-mutant
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.7.7
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Clean up your code by encapsulating business logic in mutations!
112
+ test_files: []