scoped-concerns 0.1.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: 244c3ca326094f41d147f31cfd45f6335fa601e7d99bd6fe477f8c429bbd0657
4
+ data.tar.gz: cc65ed38693ddfe83c6fffc4993f54836a55cb51521697cf7c3d69bbeb942100
5
+ SHA512:
6
+ metadata.gz: 63a38e08a0bf82682854a5491319e55dac9185125663b47a379d9748fb71a60bd04767dc376f0d4e4a99cb394455f801bb4529869e7b056454fa48bbc880e467
7
+ data.tar.gz: 76ceec63edf7e391b8ea15aee64b35028e4b8e49a15e186e4944575a84e421a9c355037a88798f0b9cf46f629b3be2f889a8ff866f8ae8c945fde6b695a7b3c0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ tags
2
+ .ruby-version
3
+ .ruby-gemset
4
+ .gemsetrc
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Three Funky Monkeys
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/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Scoped Concerns
2
+
3
+ Scoped-Concerns is a tiny utility library to help you encapsulate responsibilities in your Ruby applications by providing a common interface and a common response object for the so called _service classes_ or how we like to call them: _concerns_.
4
+
5
+ We've been playing around with this concept in a few applications and it was evolving until this point that we feel it reusable enough to become a separated library.
6
+
7
+ ## Install
8
+
9
+ It's a Ruby gem in rubygems.org, so is as simple as:
10
+
11
+ ```
12
+ gem install scoped-concerns
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Include `Scoped::Concern` in your service (concern) class, and implement your constructor and the `run` methods with the logic for your domain. For example
18
+
19
+ ```Ruby
20
+ module MyApp
21
+ module Concerns
22
+ class ActivateUser
23
+ include Scoped::Concern
24
+
25
+ def initialize(params = {})
26
+ @user_id = params[:user_id]
27
+ end
28
+
29
+ def run
30
+ user = User.find(@user_id)
31
+ return error(user: [:not_valid]) unless user
32
+
33
+ begin
34
+ user.activate!
35
+ success(user: "Activated")
36
+ rescue => e
37
+ logger.log(e.message)
38
+ error(update: [:not_valid])
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ ```
45
+
46
+ Then you can use this concern in your endpoints logic, like:
47
+
48
+ ```Ruby
49
+ on "activate/:id" do |id|
50
+ response = MyApp::Concerns::ActivateUser.run(user_id: id)
51
+
52
+ if response.success?
53
+ json(message: "User has been activated")
54
+ else
55
+ json_error(message: [response.errors[:update], response.errors[:user]].join("\n"))
56
+ end
57
+ end
58
+ ```
59
+
60
+ `Scoped-Concerns` provides the `run`, `error` and `success` helper methods through `Concern` module and the `Scoped::Response` class as a standard response format.
61
+
62
+ `Scoped-Concerns` proposes the following conventions:
63
+
64
+ * Parameters to a concern should always be a `Hash`, even if you need only one parameter (see example above)
65
+ * A `Concern` should always return a `Scoped::Response` object. (`success` and `error` helper methods return this)
66
+
67
+ ### Response
68
+
69
+ The `Scoped::Response` class has the `result` and `errors` attributes, both of them must be hashes. The keys of these `Hash`es will depend on your application domain, but, at least, you know that you'll deal with `Hash`es.
70
+
71
+ The `Scoped::Response` class also has a `success?` instance utility method that is a wrapper to `@errors.empty?` for readability's sake.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ desc "Run tests"
2
+ task "test" do
3
+ Dir["./test/**/**_test.rb"].each do |f|
4
+ load f
5
+ end
6
+ end
data/lib/.gitkeep ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ require_relative 'scoped-concerns/response'
2
+ require_relative 'scoped-concerns/concern'
@@ -0,0 +1,25 @@
1
+ module Scoped
2
+ module Concern
3
+ def self.included(base)
4
+ base.send :include, InstanceMethods
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def run(params = {})
10
+ instance = new(params)
11
+ instance.run
12
+ end
13
+ end
14
+
15
+ module InstanceMethods
16
+ def success(results = {})
17
+ Response.new(result: results)
18
+ end
19
+
20
+ def error(errors = {})
21
+ Response.new(errors: errors)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Scoped
2
+ class InvalidType < RuntimeError;end
3
+
4
+ class Response
5
+ attr_accessor :result, :errors
6
+
7
+ def initialize(result: {}, errors: {})
8
+ raise InvalidType, "result must be a hash" unless result.is_a?(Hash)
9
+ raise InvalidType, "errors must be a hash" unless errors.is_a?(Hash)
10
+
11
+ @result = result
12
+ @errors = errors
13
+ end
14
+
15
+ def success?
16
+ @errors.empty?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ 2.4.1
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "scoped-concerns"
5
+ s.version = "0.1.0"
6
+ s.summary = "Gem for Pure Ruby Objects to encapsulate specific behavior"
7
+ s.license = "MIT"
8
+ s.description = "Gem for Pure Ruby Objects to encapsulate specific behavior"
9
+ s.authors = ["Leonardo Mateo", "Lautaro Orazi"]
10
+ s.email = ["kandalf@threefunkymonkeys.com", "taro@threefunkymonkeys.com"]
11
+ s.homepage = "https://github.com/threefunkymonkeys/scoped-concerns"
12
+ s.require_paths = ["lib"]
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ end
@@ -0,0 +1,30 @@
1
+ require_relative '../test_helper'
2
+
3
+ class MyConcern
4
+ include Scoped::Concern
5
+ end
6
+
7
+ describe Scoped::Concern do
8
+ it "should add class run method" do
9
+ assert MyConcern.respond_to?(:run)
10
+ end
11
+
12
+ it "should add instance success and error methods" do
13
+ concern = MyConcern.new
14
+
15
+ assert concern.respond_to?(:success)
16
+ assert concern.respond_to?(:error)
17
+ end
18
+
19
+ it "should return a Response instance with no errors" do
20
+ concern = MyConcern.new
21
+ result = { message: "Done" }
22
+
23
+ response = concern.success(result)
24
+
25
+ assert response.is_a?(Scoped::Response)
26
+ assert response.errors.empty?
27
+
28
+ assert_equal result, response.result
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Scoped::Response do
4
+ it "should expose result and errors" do
5
+ response = Scoped::Response.new
6
+
7
+ assert response.respond_to?(:result)
8
+ assert response.respond_to?(:errors)
9
+ end
10
+
11
+ it "should not accept other than a Hash for result" do
12
+ assert_raises(Scoped::InvalidType, "result must be a Hash") do
13
+ Scoped::Response.new(result: "Hallo")
14
+ end
15
+ end
16
+
17
+ it "should not accept other than a Hash for errors" do
18
+ assert_raises(Scoped::InvalidType, "result must be a Hash") do
19
+ Scoped::Response.new(errors: "Hallo")
20
+ end
21
+ end
22
+
23
+ it "should be successful if no errors" do
24
+ response = Scoped::Response.new(result: { message: "I'm successful" })
25
+ assert response.success?
26
+ end
27
+
28
+ it "should not be successful if errors" do
29
+ response = Scoped::Response.new(result: { message: "I'm successful" },
30
+ errors: { success: "No, you're not" })
31
+
32
+ assert !response.success?
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+ require 'pp'
4
+ require_relative '../lib/scoped-concerns'
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scoped-concerns
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Leonardo Mateo
8
+ - Lautaro Orazi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-02-19 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Gem for Pure Ruby Objects to encapsulate specific behavior
15
+ email:
16
+ - kandalf@threefunkymonkeys.com
17
+ - taro@threefunkymonkeys.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".gitignore"
23
+ - LICENSE.md
24
+ - README.md
25
+ - Rakefile
26
+ - lib/.gitkeep
27
+ - lib/scoped-concerns.rb
28
+ - lib/scoped-concerns/concern.rb
29
+ - lib/scoped-concerns/response.rb
30
+ - ruby-version.sample
31
+ - scoped-concerns.gemspec
32
+ - test/concern/concern_test.rb
33
+ - test/concern/response_test.rb
34
+ - test/test_helper.rb
35
+ homepage: https://github.com/threefunkymonkeys/scoped-concerns
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.7.6
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Gem for Pure Ruby Objects to encapsulate specific behavior
59
+ test_files: []