light_service_object 0.1.5 → 0.1.6

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: 100d278a461065875533bd01459a32689b7b9decf705b9cd4400675a056ad441
4
- data.tar.gz: 7d7bf77c96b317568ad5ddc612f1edf7c864a0cc7970842b5649c3e954a9dccf
3
+ metadata.gz: 6a4e68067319da840f48462ed29d2fdb32314e14c78c543f6e978b345d2d87b7
4
+ data.tar.gz: 0fb567f252a98e5bef84d9d2b7db469e86b6b9bdce13038dd701f703c5be474d
5
5
  SHA512:
6
- metadata.gz: 7ce179e98cee24693c5b9e74645cfa4cb028ed4bd48f0375ce04848323172651033d2878b010ccaa697e371eef97f4f01696c60d12df978785c39a1fc3784a9e
7
- data.tar.gz: fca061f22fd49eba170a38486c2a4debe4c2d9e725d01587866c1d69308b828e9680d186406fb1293e29c617117254b23e2b6cea8fbb12ea9853bfdf8d011836
6
+ metadata.gz: edb266a2036ce57aba328e8c7fe3925b1955accd7537c4cdf7ff8ea14111eaa1234c33c974d611909031869998a648277abff83f4e3431e4391e14443da172f3
7
+ data.tar.gz: 9e6faf7bd3f116726ab2260401f7d5e9b03c41135c377bf46f37a498ad6c57026928590c147feb442c3b681cbf8c755e4207dbc00b2981869bb70a7ccafb20e0
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ light_service_object (0.1.6)
5
+ dry-initializer (~> 2.0)
6
+ dry-monads (~> 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.1.5)
12
+ diff-lcs (1.3)
13
+ dry-core (0.4.9)
14
+ concurrent-ruby (~> 1.0)
15
+ dry-equalizer (0.2.2)
16
+ dry-initializer (2.5.0)
17
+ dry-monads (1.3.1)
18
+ concurrent-ruby (~> 1.0)
19
+ dry-core (~> 0.4, >= 0.4.4)
20
+ dry-equalizer
21
+ rake (10.5.0)
22
+ rspec (3.8.0)
23
+ rspec-core (~> 3.8.0)
24
+ rspec-expectations (~> 3.8.0)
25
+ rspec-mocks (~> 3.8.0)
26
+ rspec-core (3.8.2)
27
+ rspec-support (~> 3.8.0)
28
+ rspec-expectations (3.8.4)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.8.0)
31
+ rspec-mocks (3.8.1)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.8.0)
34
+ rspec-support (3.8.2)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ bundler (~> 2.0)
41
+ light_service_object!
42
+ rake (~> 10.0)
43
+ rspec (~> 3.0)
44
+
45
+ BUNDLED WITH
46
+ 2.0.2
data/README.md CHANGED
@@ -14,15 +14,59 @@ And then execute:
14
14
 
15
15
  $ bundle
16
16
 
17
- ## Usage
17
+ ## A Light Service Object with a Contract
18
18
 
19
- TODO: Write usage instructions here
19
+ Service objects are a great way to encapsulate business/domain functionality in a Rails app.
20
20
 
21
- ## Development
21
+ ### The Old Way
22
22
 
23
- 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.
23
+ They typically wrap some functionality up in a `call` method, with an initializer for setting parameters.
24
+
25
+ ```
26
+ class TypicalServiceObject
27
+ def initialize(date, number)
28
+ @date = date
29
+ @number = number
30
+ end
31
+
32
+ def call
33
+ @date = Date.parse(@date) if @date.is_a?(String)
34
+ If @date - Date.today < 7 then
35
+ @number += 10
36
+ else
37
+ raise ArgumentError.new("Date is too far away")
38
+ end
39
+ @number
40
+ end
41
+ end
42
+ ```
43
+
44
+ This service object has a few problems:
45
+ - No indication of what it's "contract" is with the outside world
46
+ - No way to indicate failure other than Exceptions
47
+ - Manual conversion of data into the expected form
48
+
49
+ ### The New Way
50
+
51
+ ```
52
+ class NewServiceObject < LightServiceObject::Base
53
+ required :date, ensure: Date
54
+ optional :number
55
+
56
+ def perform
57
+ fail!("Date is too far away") if date - Date.today >= 7
58
+
59
+ number + 10
60
+ end
61
+ end
62
+ ```
63
+
64
+ - date is required, a failure will be returned with the error message
65
+ - date will be transformed into a Date if it isn't one already `ensure: Date`
66
+ - `fail!(message)` causes the service to return a failure and message
67
+ - the last thing evaluated will be returned as the result `number + 10`
68
+ - one side note: all parameters are immutable by default
24
69
 
25
- 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).
26
70
 
27
71
  ## Contributing
28
72
 
data/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -1,3 +1,3 @@
1
1
  module LightServiceObject
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -36,37 +36,55 @@ module LightServiceObject
36
36
 
37
37
 
38
38
  ## — CLASS METHODS
39
- def self.result_class
40
- @result_class
41
- end
39
+ class << self
40
+ def result_class
41
+ @result_class
42
+ end
42
43
 
43
- def self.param(key, **options)
44
- raise Error.new("Do not use param in a service object")
45
- end
44
+ def param(key, **options)
45
+ raise Error.new("Do not use param in a service object")
46
+ end
46
47
 
47
- def self.required(key, **options)
48
- option key, **options
49
- end
48
+ def option(*args, **opts, &block)
49
+ if opts.delete(:mutable)
50
+ self.send("attr_writer", args.first)
51
+ end
52
+ super(*args, **opts, &block)
53
+ end
50
54
 
51
- def self.optional(key, **options)
52
- options[:optional] = true
53
- option(key, **options)
54
- end
55
+ def required(key, **options)
56
+ options[:private] = true
57
+ option(key, **options)
58
+ end
55
59
 
56
- def self.expected_result_class(klass)
57
- @result_class = klass
58
- @result_class = klass.constantize if klass.is_a?(String)
59
- end
60
+ def optional(key, **options)
61
+ options[:optional] = true
62
+ options[:private] = true
63
+ option(key, **options)
64
+ end
60
65
 
61
- def self.call(**options)
62
- obj = self.new(**options)
66
+ def expected_result_class(klass)
67
+ @result_class = klass
68
+ @result_class = klass.constantize if klass.is_a?(String)
69
+ end
63
70
 
64
- # Identify incoming params that weren't specified
65
- # set_params = obj.instance_variables.map{|e| e.to_s.tr("@","").to_sym }
66
- # unknown_params = (options.keys - set_params)
67
- # ap("#{self.name} > Unknown Parameters #{unknown_params}") if unknown_params.present?
71
+ def call(**options)
72
+ begin
73
+ obj = self.new(**options)
74
+ rescue KeyError => e
75
+ return Dry::Monads.Failure(e.message)
76
+ end
77
+
78
+ # Identify incoming params that weren't specified
79
+ # set_params = obj.instance_variables.map{|e| e.to_s.tr("@","").to_sym }
80
+ # unknown_params = (options.keys - set_params)
81
+ # ap("#{self.name} > Unknown Parameters #{unknown_params}") if unknown_params.present?
82
+
83
+ result = obj.call
84
+ end
85
+ end
68
86
 
69
- result = obj.call
87
+ def self.failed(error)
70
88
  end
71
89
 
72
90
  ## — INSTANCE METHODS
@@ -76,7 +94,7 @@ module LightServiceObject
76
94
 
77
95
  def call
78
96
  result = self.perform
79
- if self.result_class.present?
97
+ if self.result_class
80
98
  if !result.is_a?(self.result_class)
81
99
  a_name = "#{self.result_class}"
82
100
  a_name = %w[a e i o u y].include?(a_name.first.downcase) ? "an #{a_name}" : "a #{a_name}"
@@ -86,19 +104,19 @@ module LightServiceObject
86
104
  end
87
105
  Dry::Monads.Success(result)
88
106
  rescue StandardError => error
89
- reason = self.error_reason(error)
90
- self.class.failed(error)
91
- Dry::Monads.Failure(reason)
107
+ fail!(error)
92
108
  end
93
109
 
94
110
  def fail!(error)
95
111
  error = ::StandardError.new(error.to_s) if !error.is_a?(::StandardError)
96
- raise error
112
+ reason = self.error_reason(error)
113
+ self.class.failed(error)
114
+ Dry::Monads.Failure(reason)
97
115
  end
98
116
 
99
117
  def error_reason(error)
100
118
  # Give subclasses a chance to see errors first
101
- "#{self.class}: #{error}"
119
+ "[#{self.class}] #{error}"
102
120
  end
103
121
  end
104
122
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light_service_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sharpe
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-28 00:00:00.000000000 Z
11
+ date: 2019-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -92,10 +92,12 @@ files:
92
92
  - ".travis.yml"
93
93
  - CHANGELOG.md
94
94
  - Gemfile
95
+ - Gemfile.lock
95
96
  - LICENSE.txt
96
97
  - README.md
97
98
  - Rakefile
98
99
  - bin/console
100
+ - bin/rspec
99
101
  - bin/setup
100
102
  - lib/light_service_object.rb
101
103
  - lib/light_service_object/version.rb
@@ -119,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  - !ruby/object:Gem::Version
120
122
  version: '0'
121
123
  requirements: []
122
- rubygems_version: 3.0.3
124
+ rubygems_version: 3.0.6
123
125
  signing_key:
124
126
  specification_version: 4
125
127
  summary: A lightweight base service object for Rails/Ruby