light_service_object 0.1.5 → 0.1.6

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 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