service_record 1.2.4 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7916d1e6a73deee6ce9dddf92550452365db224960d08d4171db0581bc67fde
4
- data.tar.gz: 57d614b6361e6643890c88730100fe33b490c109962d66e4dae241a985bf9e42
3
+ metadata.gz: 761226eff3ab278171ca2a9250b6fe089ceb53eeb2b1e221b680d250c3f1d2be
4
+ data.tar.gz: 567e4aa90fff412e1d42eba985a9e7a3f6397a53d622ec7e996503e22aa78a75
5
5
  SHA512:
6
- metadata.gz: 4e4807fa30e0d3b053dd769078c8d3938eb02ad7de3f14812fa3bf9a6442f38652a317bff66ac4765c273b1b29c24697ae71cc857040263de03df4361869f4cd
7
- data.tar.gz: '0488df45e2d0177e24db8f1f88077ccc94b1e8c91e7612a6176ad70f99802561fe0f774e61a73eaccaf0a0c1ce9cfaf4b6223a0cbe1a4743877305e389924e8f'
6
+ metadata.gz: 24c06c7384fca171053cd271ef96107ee36753015bd4198ed1b6f87e4ea5fe68db663d4a7a9e7b50af6cd8a03d71bce575ff3e17d8ffba2045442b55e8dafb19
7
+ data.tar.gz: 2889e28b5f8507849beaef07ce99fd886063a4cf40c91d035ad92190788d8322d956e0315aa94a85a067471671a36d634171e84a26d56c65692fd651c0b998de
data/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # ServiceRecord
2
2
 
3
+ [![Gem](https://img.shields.io/gem/v/service_record)](https://rubygems.org/gems/service_record)
3
4
  [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/uxxman/service_record/CI)](https://github.com/uxxman/service_record/actions?query=workflow%3ACI)
4
5
  [![Code Climate coverage](https://img.shields.io/codeclimate/coverage/uxxman/service_record)](https://codeclimate.com/github/uxxman/service_record)
5
6
  [![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/uxxman/service_record)](https://codeclimate.com/github/uxxman/service_record)
6
- [![Gem](https://img.shields.io/gem/v/service_record)](https://rubygems.org/gems/service_record)
7
7
 
8
8
  An ActiveRecord lookalike but for business model requirements, a.k.a Service Objects.
9
9
 
10
10
  Rails is packed with amazing tools to get you started with building your new awesome project and enforces reliable and battle-tested guidelines. One of those guideline is "**thin controllers and fat models**", but sometimes (actually most of the time) its difficult to follow because most business requirements are not that simple like most CRUD operations.
11
11
 
12
- Enters, ServiceRecord. Its similar to ActiveRecord models but their sole purpose is to perform a big/complex/muilt-step task without bloating the controllers or models.
12
+ Enters, ServiceRecord, a tiny wrapper around basic goodies included in Rails. Its similar to ActiveRecord models but their sole purpose is to perform a big/complex/muilt-step task without bloating the controllers or models.
13
13
 
14
14
  ## Installation
15
15
 
@@ -66,9 +66,7 @@ The returned response from a service will have the following useful attributes/m
66
66
  * `result` contains returned value of service perform function
67
67
  * `errors` contains details about issues that occurr while performing the service
68
68
 
69
- There is a **perform!** (with a bang !) method which will raise **ServiceRecord::Failure** in case of service failure.
70
-
71
-
69
+ There is also a **perform!** (with a bang !) method which will raise **ServiceRecord::Failure** in case of service failure.
72
70
 
73
71
  ## Example
74
72
 
@@ -83,12 +81,12 @@ def sign_in
83
81
  errors = []
84
82
 
85
83
  # Basic validation
86
- errors << 'Email is required' if params[:email].blank?
87
- errors << 'Email is invalid' if params[:email].present? && /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.match?(params[:email])
84
+ errors << 'Email is required' if params[:email].blank?
85
+ errors << 'Email is invalid' if params[:email].present? && /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.match?(params[:email])
88
86
  errors << 'Password is required' if params[:password].blank?
89
87
 
90
88
  if errors.size == 0
91
- user = User.find_by(email: params[:email]).try(:authenticate, params[:password])
89
+ user = User.find_by(email: params[:email])&.try(:authenticate, params[:password])
92
90
 
93
91
  if user.present?
94
92
  token = JsonWebToken.encode(user_id: user.id)
@@ -119,9 +117,11 @@ class AuthenticateUser < ApplicationService
119
117
  def perform
120
118
  user = User.find_by(email: email).try(:authenticate, password)
121
119
 
122
- return JsonWebToken.encode(user_id: user.id) if user.present?
123
-
124
- errors.add :authentication, 'invalid credentials'
120
+ if user.present?
121
+ JsonWebToken.encode(user_id: user.id)
122
+ else
123
+ errors.add :authentication, 'invalid credentials'
124
+ end
125
125
  end
126
126
  end
127
127
 
@@ -174,7 +174,9 @@ Availble callbacks are `before_perform`, `after_perform` and `around_perform`. I
174
174
 
175
175
  ## Development
176
176
 
177
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
177
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
178
+
179
+ ServiceRecord uses appraisals to test the code base against multiple versions of Rails ActiveModel. When first developing, you need to run `bundle install` and then `bundle exec appraisal install`, to install the different gem sets. You can then run all appraisal files (like CI does), with `appraisal rake`.
178
180
 
179
181
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
180
182
 
@@ -1,7 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/generators/named_base'
2
4
 
3
5
  module Rails
4
6
  module Generators
7
+ # Create AppicationService and SubService classes using Rails generators.
8
+ #
9
+ # E.g:
10
+ # bin/rails service my_service
11
+ #
5
12
  class ServiceGenerator < Rails::Generators::NamedBase
6
13
  desc 'This generator creates a service file at app/services'
7
14
 
@@ -1,25 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
1
4
  require 'service_record/failure'
5
+ require 'service_record/response'
2
6
  require 'service_record/callbacks'
3
7
 
4
8
  module ServiceRecord
9
+ # Base class to be extended by all service classes
10
+ #
11
+ # class MyService < ServiceRecord
12
+ # end
13
+ #
5
14
  class Base
6
15
  include Callbacks
7
16
  include ActiveModel::Attributes
8
17
  include ActiveModel::Validations
9
18
  include ActiveModel::AttributeAssignment
10
19
 
20
+ attr_accessor :result
21
+
22
+ # Wrapper around the *perform* instance method that runs all the validations
23
+ # and callbacks before eventually calling *perform*.
11
24
  def self.perform(args = {})
12
25
  new.tap do |service|
13
26
  service.attributes = args
14
- break service unless service.valid?
15
27
 
16
- service.run_callbacks :perform do
17
- service.result = service.perform
18
- service.result = nil if service.failure?
28
+ if service.valid?
29
+ service.run_callbacks :perform do
30
+ service.result = service.perform
31
+ end
19
32
  end
33
+
34
+ return Response.new(service.result, service.errors)
20
35
  end
21
36
  end
22
37
 
38
+ # Wapper around the *perform* class method that raises exception if service fails
23
39
  def self.perform!(args = {})
24
40
  service = perform(args)
25
41
  return service if service.success?
@@ -27,16 +43,7 @@ module ServiceRecord
27
43
  raise Failure, service
28
44
  end
29
45
 
30
- attr_accessor :result
31
-
32
- def success?
33
- errors.empty?
34
- end
35
-
36
- def failure?
37
- !success?
38
- end
39
-
46
+ # Each subclass must define the *perform* method
40
47
  def perform
41
48
  raise NotImplementedError
42
49
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ServiceRecord
4
+ # Defines before/around/after callbacks for the 'perform' method
2
5
  module Callbacks
3
6
  extend ActiveSupport::Concern
4
7
 
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ServiceRecord
4
+ # Exception to be raised when a service fails
2
5
  class Failure < StandardError
3
6
  attr_reader :service
4
7
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ServiceRecord
4
+ # Response to be returned by a service when it finishes
5
+ class Response
6
+ attr_reader :result, :errors
7
+
8
+ def initialize(result, errors)
9
+ @result = result
10
+ @errors = errors
11
+ end
12
+
13
+ # Checks for errors. Returns +true+ if no errors are found, +false+ otherwise.
14
+ def success?
15
+ errors.empty?
16
+ end
17
+
18
+ # Checks for errors. Returns +false+ if no errors are found, +true+ otherwise.
19
+ def failure?
20
+ !success?
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ServiceRecord
2
- VERSION = '1.2.4'.freeze
4
+ VERSION = '1.4.0'
3
5
  end
@@ -1,2 +1,4 @@
1
- require 'active_model'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'service_record/base'
4
+ require 'service_record/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: service_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muhammad Usman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-20 00:00:00.000000000 Z
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -16,14 +16,158 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '6.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: appraisal
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-packaging
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.5.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.5.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.14'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.14.3
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.14'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.14.3
103
+ - !ruby/object:Gem::Dependency
104
+ name: rubocop-rails
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.15'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 2.15.2
113
+ type: :development
114
+ prerelease: false
115
+ version_requirements: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '2.15'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 2.15.2
123
+ - !ruby/object:Gem::Dependency
124
+ name: rubocop-rake
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 0.6.0
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: 0.6.0
137
+ - !ruby/object:Gem::Dependency
138
+ name: rubocop-rspec
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '2.12'
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 2.12.1
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '2.12'
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: 2.12.1
157
+ - !ruby/object:Gem::Dependency
158
+ name: simplecov
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: 0.17.1
164
+ type: :development
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: 0.17.1
27
171
  description: ActiveRecord lookalike but for business model requirements
28
172
  email:
29
173
  - uxman.sherwani@gmail.com
@@ -42,6 +186,7 @@ files:
42
186
  - lib/service_record/base.rb
43
187
  - lib/service_record/callbacks.rb
44
188
  - lib/service_record/failure.rb
189
+ - lib/service_record/response.rb
45
190
  - lib/service_record/version.rb
46
191
  homepage: https://github.com/uxxman/service_record
47
192
  licenses:
@@ -49,8 +194,9 @@ licenses:
49
194
  metadata:
50
195
  homepage_uri: https://github.com/uxxman/service_record
51
196
  source_code_uri: https://github.com/uxxman/service_record
197
+ rubygems_mfa_required: 'true'
52
198
  changelog_uri: https://github.com/uxxman/service_record/releases
53
- post_install_message:
199
+ post_install_message:
54
200
  rdoc_options: []
55
201
  require_paths:
56
202
  - lib
@@ -58,15 +204,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
204
  requirements:
59
205
  - - ">="
60
206
  - !ruby/object:Gem::Version
61
- version: 2.5.0
207
+ version: 2.7.5
62
208
  required_rubygems_version: !ruby/object:Gem::Requirement
63
209
  requirements:
64
210
  - - ">="
65
211
  - !ruby/object:Gem::Version
66
212
  version: '0'
67
213
  requirements: []
68
- rubygems_version: 3.1.2
69
- signing_key:
214
+ rubygems_version: 3.3.7
215
+ signing_key:
70
216
  specification_version: 4
71
217
  summary: Service objects for rails
72
218
  test_files: []