telephone 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: 2961c1545d60c8daef9cdc90a8ecea01c12ecd14357d446dbfe86cae84cc43c2
4
+ data.tar.gz: 27dad4361e48e380776fb3c32ea59855f95804e024b1aad879d84ad292f96a23
5
+ SHA512:
6
+ metadata.gz: 70159c4118b77a694873f4cf9f14d28bfbaae52692c28eaa95eafec80b06a91e8fd65dd76db1a849efdd5e7b5a294c5d1836a5b924c6df81eb9b9a636145c14e
7
+ data.tar.gz: 2bd95f410bc0bc92960c1e6065ecf5b0971dbc6792dff760cebef1494d1cdbc8efd5e87499d53a7eaae1786f8904a4280b570c9d59327995877a17fad20a8773
data/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # Telephone ☎️
2
+
3
+ ![](https://github.com/bharget/telephone/actions/workflows/ci.yml/badge.svg)
4
+
5
+ Telephone is a light weight utility that helps you create and call service objects from anywhere within your application.
6
+
7
+ Telepone comes with a simple interface that helps with:
8
+
9
+ * Keeping your code DRY
10
+ * Encapsulating complex logic in a more readable way
11
+ * Making your code easier to test
12
+ * Gracefully handling errors and validations
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'telephone'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle install
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install telephone
29
+
30
+ ## Usage
31
+
32
+ `Telephone::Service` is a simple utility class for creating and calling service objects. It allows you to define arguments and validations, and provides
33
+ a simple interface for calling the service and determining its success.
34
+
35
+ To start, define an `ApplicationService` and inherit from `Telephone::Service`.
36
+
37
+ ```ruby
38
+ # /app/services/application_service.rb
39
+
40
+ class ApplicationService < Telephone::Service
41
+ end
42
+ ```
43
+
44
+ A very simple example of a service object:
45
+
46
+ ```ruby
47
+ class SimpleExample < ApplicationService
48
+ def call
49
+ "Hello World"
50
+ end
51
+ end
52
+
53
+ s = SimpleExample.call #=> <#SimpleExample @result="Hello World">
54
+ s.success? #=> true
55
+ s.result #=> "Hello World"
56
+ ```
57
+
58
+ ### Arguments
59
+
60
+ You can define arguments for the service object. These arguments will be passed to the service object's `call` method, and will be available as an attribute.
61
+
62
+ ```ruby
63
+ class SimpleExample < ApplicationService
64
+ argument :name
65
+
66
+ def call
67
+ "Hello, #{name}."
68
+ end
69
+ end
70
+
71
+ SimpleExample.call(name: "Benjamin").result #=> "Hello, Benjamin."
72
+ ```
73
+
74
+ Arguments can also be required, which will prevent the service object from executing unless they are present.
75
+
76
+ ```ruby
77
+ class SimpleExample < ApplicationService
78
+ argument :name, required: true
79
+
80
+ def call
81
+ "Hello, #{name}."
82
+ end
83
+ end
84
+
85
+ s = SimpleExample.call
86
+ s.success? #=> false
87
+ s.errors.full_messages #=> ["Name can't be blank"]
88
+ s.result #=> nil
89
+ ```
90
+
91
+ You can also give a default value for an argument.
92
+
93
+ ```ruby
94
+ argument :name, default: "Benjamin"
95
+ ```
96
+
97
+ ### Validations
98
+
99
+ Since `Telephone::Service` includes `ActiveModel::Model`, you can define validations in the same way you would for an ActiveRecord model.
100
+
101
+ ```ruby
102
+ validates :name, format: { with: /\A[a-zA-Z]+\z/ }
103
+ validate :admin_user?
104
+
105
+ def admin_user?
106
+ errors.add(:user, "not admin") unless user.admin?
107
+ end
108
+ ```
109
+
110
+ If a validation fails, the service object will not execute and return `nil` as the result of th call. You can check the status of the service object by calling `success?`.
111
+
112
+ ```ruby
113
+ s = SomeService.call
114
+ s.success? #=> false
115
+ ```
116
+
117
+ ## Best Practices
118
+
119
+ Service objects are a great way to keep your code DRY and encapsulate business logic. As a rule of thumb, try to keep your service objects to a single responsibility. If you find yourself dealing with very complex logic, consider breaking it up into smaller services.
120
+
121
+ ## Development
122
+
123
+ After checking out the repo, run `bin/setup` to install dependencies. This will install the dependencies for each subgem and run the entire test suite.
124
+
125
+ To experiment, you can run `bin/console` for an interactive prompt.
126
+
127
+ ### Documentation
128
+
129
+ This project is documented using YARD. All code should be well documented via the YARD syntax prior to merging.
130
+
131
+ You can access the docmentation by starting up the YARD server.
132
+
133
+ ```sh
134
+ yard server --reload
135
+ ```
136
+
137
+ The `--reload`, or `-r`, flag tells the server to auto reload the documentation on each request.
138
+
139
+ Once the server is running, the documentation will by available at http://localhost:8808
data/lib/telephone.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "telephone/service"
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ module Telephone
6
+ class Service
7
+ include ActiveModel::Model
8
+
9
+ ##
10
+ # The primary outcome of the service object. For consistency,
11
+ # all service objects always return +self+. If you need a value
12
+ # returned, the return value of +#call+ will be available on the
13
+ # attribute +@result+.
14
+ #
15
+ # @example
16
+ # Telephone::Service.call(foo: bar).result # "baz"
17
+ attr_accessor :result
18
+
19
+ ##
20
+ # Determines whether or not the action of the service
21
+ # object was successful.
22
+ #
23
+ # @example
24
+ # Telephone::Service.call(foo: bar).success? # true
25
+ #
26
+ # @return [Boolean] whether or not the action succeeded.
27
+ def success?
28
+ errors.empty?
29
+ end
30
+
31
+ class << self
32
+ ##
33
+ # Defines a getter/setter for a service object argument. This also allows you
34
+ # to pass in a default, or set the argument to "required" to add a validation
35
+ # that runs before executing the block.
36
+ #
37
+ # @example
38
+ # class SomeService < Telephone::Service
39
+ # argument :foo, default: "bar"
40
+ # argument :baz, required: true
41
+ #
42
+ # def call
43
+ # puts foo
44
+ # puts baz
45
+ # end
46
+ # end
47
+ def argument(arg, default: nil, required: false)
48
+ send(:attr_accessor, arg.to_sym)
49
+ send(:validates, arg.to_sym, presence: true) if required
50
+
51
+ defaults[arg.to_sym] = default
52
+ end
53
+
54
+ ##
55
+ # Used to maintain a list of default values to set prior to initialization
56
+ # based on the options in #argument.
57
+ def defaults
58
+ @defaults ||= {}
59
+ end
60
+
61
+ ##
62
+ # Executes the service object action directly from the class — similar to the
63
+ # way a Proc can be executed with `Proc#call`. This allows us to add some common
64
+ # logic around running validations and setting argument defaults.
65
+ #
66
+ # @example
67
+ # Telephone::Service.call(foo: bar)
68
+ def call(**args)
69
+ instance = new(defaults.merge(args))
70
+ instance.result = instance.call if instance.valid?
71
+ instance
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telephone
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: telephone
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin Hargett
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-07-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Utility class for creating and calling service objects.
28
+ email: hargettbenjamin@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - README.md
34
+ - lib/telephone.rb
35
+ - lib/telephone/service.rb
36
+ - lib/telephone/version.rb
37
+ homepage: https://github.com/bharget/telephone
38
+ licenses: []
39
+ metadata:
40
+ bug_tracker_uri: https://github.com/bharget/telephone/issues
41
+ changelog_uri: https://github.com/bharget/telephone/blob/master/CHANGELOG.md
42
+ source_code_uri: https://github.com/bharget/telephone
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 2.6.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements:
58
+ - none
59
+ rubygems_version: 3.0.3
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Utility class for creating and calling service objects.
63
+ test_files: []