keka 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e4644a49e6ff908024e1ec91cdeec0d7a6886c9d
4
- data.tar.gz: 6a89ab5dab98c71ab7f77a1ddfed84419e956eed
2
+ SHA256:
3
+ metadata.gz: 441fd2d2712b2ea5b6a15076088de3a1617945f0683251addd7e0be5f5077b9e
4
+ data.tar.gz: 3d7cf921207b9000a838197669af05d619aadc1252b420d48d74771266dfbccf
5
5
  SHA512:
6
- metadata.gz: b2ba159cfc8a028f3f834cd2b48af5184da28f8b2d85a36ad62711b3771754f812b8f01c60e426f7f39c441eb30c4dc8b7b1eabda0632a970dc94767c13c41c7
7
- data.tar.gz: 62b1c97c626ff58d1e51b033259b9d18bf0c0f71594a73549150f6b6b37aeff5d58944c5d591564fc78ac43975b1ef16bb50725cd3f67d354e2ddb3e17917c9e
6
+ metadata.gz: 447a280a18b005007788861863dce8b2dc647100add773615a1f5e2ae1a1151020f3955b0486da070a8995e32b7c9b168f5da5adf652b8fb8cb535e1e6b1b151
7
+ data.tar.gz: 7514d83dd424338c51254855275b4031d45ba34a4814104130a2549aad7e0676327e288edfb1422b08a899d0528ffc48a93f8822a574f17d6af346a749ab57a3
@@ -0,0 +1,17 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: circleci/ruby:2.5.3
6
+ working_directory: ~/repo
7
+ environment:
8
+ BUNDLER_VERSION: 1.17.3
9
+ steps:
10
+ - checkout
11
+ - run: gem install bundler:1.17.3
12
+ - run:
13
+ name: install dependencies
14
+ command: bundle install --jobs=4 --retry=3 --path vendor/bundle
15
+ - run:
16
+ name: run specs
17
+ command: bundle exec rspec
@@ -0,0 +1 @@
1
+ 2.5.3
@@ -0,0 +1,10 @@
1
+ # CHANGELOG
2
+
3
+ ## Unreleased
4
+
5
+ ## Version 0.2.0
6
+ * Support `.rescue_with` to handle exceptions in `.run` block.
7
+ * Add CI.
8
+
9
+ ## Version 0.1.0
10
+ * Initial release.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- keka (0.1.0)
4
+ keka (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -13,19 +13,19 @@ GEM
13
13
  coderay (~> 1.1.0)
14
14
  method_source (~> 0.9.0)
15
15
  rake (10.5.0)
16
- rspec (3.8.0)
17
- rspec-core (~> 3.8.0)
18
- rspec-expectations (~> 3.8.0)
19
- rspec-mocks (~> 3.8.0)
20
- rspec-core (3.8.0)
21
- rspec-support (~> 3.8.0)
22
- rspec-expectations (3.8.2)
16
+ rspec (3.9.0)
17
+ rspec-core (~> 3.9.0)
18
+ rspec-expectations (~> 3.9.0)
19
+ rspec-mocks (~> 3.9.0)
20
+ rspec-core (3.9.1)
21
+ rspec-support (~> 3.9.1)
22
+ rspec-expectations (3.9.0)
23
23
  diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.8.0)
25
- rspec-mocks (3.8.0)
24
+ rspec-support (~> 3.9.0)
25
+ rspec-mocks (3.9.1)
26
26
  diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.8.0)
28
- rspec-support (3.8.0)
27
+ rspec-support (~> 3.9.0)
28
+ rspec-support (3.9.2)
29
29
 
30
30
  PLATFORMS
31
31
  ruby
@@ -38,4 +38,4 @@ DEPENDENCIES
38
38
  rspec (~> 3.7)
39
39
 
40
40
  BUNDLED WITH
41
- 1.16.2
41
+ 1.17.3
data/README.md CHANGED
@@ -4,44 +4,34 @@ Keka (Japanese for 'result') is a wrapper that represents the result of a partic
4
4
 
5
5
  ## Installation
6
6
 
7
- Add this line to your application's Gemfile:
8
-
9
7
  ```ruby
10
8
  gem 'keka'
11
9
  ```
12
10
 
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- Or install it yourself as:
18
-
19
- $ gem install keka
20
-
21
11
  ## Usage
22
12
 
23
13
  Below is an example of how the various methods can come together.
24
14
 
25
15
  ```ruby
26
16
  class Order
27
- def refund
17
+ def refund(cancel_delivery = true)
28
18
  Keka.run do
29
19
  # returns an err keka with provided msg if !refundable?
30
20
  Keka.err_unless!(refundable?, 'Payment is no longer refundable.')
31
21
  # returns an err keka with provided msg if !refund!
32
- Keka.err_unless!(refund!, 'Refund failed. Please try again')
22
+ Keka.err_unless!(payment.refund, 'Refund failed. Please try again')
33
23
  # execute statements if nothing 'return' from above
34
24
  do_something_else
35
- # if cancel_delivery?
36
- # => returns an err keka with provided msg if !remove_delivery
37
- Keka.err_unless!(remove_delivery, 'Refunded but failed to remove delivery.') if cancel_delivery?
25
+ # if cancel_delivery
26
+ # => returns an err keka with provided msg if !remove_delivery_assignment
27
+ Keka.err_unless!(remove_delivery_assignment, 'Refunded but failed to remove delivery.') if cancel_delivery
38
28
  # returns an ok keka if nothing 'return' from above
39
29
  end
40
30
  end
41
31
 
42
32
  private
43
33
 
44
- def remove_delivery
34
+ def remove_delivery_assignment
45
35
  Keka.run do
46
36
  # returns an ok keka if already_removed?
47
37
  Keka.ok_if! already_removed?
@@ -64,9 +54,56 @@ class SomeController
64
54
  end
65
55
  ```
66
56
 
67
- Of course, you can also use `.err_unless!`, `err_if!`, and `ok_if!` outside
57
+ Of course, you can also use `.err_unless!`, `.err_if!`, and `.ok_if!` outside
68
58
  of the `Keka.run` block.
69
59
 
60
+ ### Handle Exceptions
61
+
62
+ Before version 0.2.0, handling exceptions in `.run` block is a bit tricky. You might do something like this
63
+
64
+ ```ruby
65
+ def validate_purchase(item_ids)
66
+ Keka.run do
67
+ Item.find(item_ids)
68
+ rescue ActiveRecord::RecordNotFound
69
+ Keka.err_if! true, 'Some item is unavailable'
70
+ end
71
+ end
72
+ ```
73
+
74
+ After version 0.2.0, you can simply
75
+ ```ruby
76
+ # * Returns ok result if no exception is raised.
77
+ # * Returns err result if ActiveRecord::RecordNotFound is raised, with msg set
78
+ # to 'Some item is unavailable'.
79
+ # * Raises if any other non-keka exception is thrown.
80
+ def validate_purchase(item_ids)
81
+ Keka.rescue_with(ActiveRecord::RecordNotFound, 'Some item is unavailable')
82
+ .run { Item.find(item_ids) }
83
+ end
84
+ ```
85
+
86
+ You can also chain `.rescue_with`
87
+ ```ruby
88
+ def validate_purchase(store_id, new_item_payload)
89
+ Keka.rescue_with(ActiveRecord::RecordNotFound, 'Some item is unavailable')
90
+ .rescue_with(ActiveRecord::RecordInvalid, 'Invalid payload')
91
+ .run do
92
+ store = Store.find(store_id)
93
+ store.items.create!(new_item_payload)
94
+ end
95
+ end
96
+ ```
97
+
98
+ Note, by design, `.rescue_with` only rescues from descendants of StandardError. This will **NOT** work.
99
+ ```ruby
100
+ def invalid_example
101
+ # The .rescue_with does NOTHING here. This method will raise a NoMemoryError exception.
102
+ Keka.rescue_with(NoMemoryError, 'oops')
103
+ .run { raise NoMemoryError.new }
104
+ end
105
+ ```
106
+
70
107
  ## Development
71
108
 
72
109
  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.
@@ -1,72 +1,44 @@
1
1
  require 'keka/version'
2
+ require 'keka/exceptions'
3
+ require 'keka/result'
4
+ require 'keka/context'
2
5
 
3
6
  module Keka
7
+ class << self
8
+ include Context::Originable
4
9
 
5
- class Halt < StandardError
6
- attr_reader :keka
7
- def initialize(keka)
8
- @keka = keka
9
- super
10
+ def err_if!(evaluator, msg = nil)
11
+ raise Halt.new(err(msg)) if (evaluator.respond_to?(:ok?) ? evaluator.ok? : evaluator)
10
12
  end
11
- end
12
-
13
- class Base
14
- attr_accessor :msg
15
13
 
16
- def initialize(is_success, msg)
17
- @is_success = is_success
18
- @msg = msg
14
+ def err_unless!(evaluator, msg = nil)
15
+ if evaluator.is_a? self::Result
16
+ return if evaluator.ok?
17
+ evaluator.msg = msg if msg
18
+ raise Halt.new(evaluator)
19
+ else
20
+ raise Halt.new(err(msg)) unless evaluator
21
+ end
19
22
  end
20
23
 
21
- def ok?
22
- is_success
24
+ def ok_if!(evaluator, msg = nil)
25
+ if evaluator.is_a? self::Result
26
+ return unless evaluator.ok?
27
+ evaluator.msg = msg if msg
28
+ raise Halt.new(evaluator)
29
+ else
30
+ raise Halt.new(ok(msg)) if evaluator
31
+ end
23
32
  end
24
33
 
25
- private
26
- attr_reader :is_success
27
- end
28
-
29
- def self.err_if!(evaluator, msg = nil)
30
- raise Halt.new(err(msg)) if (evaluator.respond_to?(:ok?) ? evaluator.ok? : evaluator)
31
- end
32
-
33
- def self.err_unless!(evaluator, msg = nil)
34
- if evaluator.is_a? self::Base
35
- return if evaluator.ok?
36
- evaluator.msg = msg if msg
37
- raise Halt.new(evaluator)
38
- else
39
- raise Halt.new(err(msg)) unless evaluator
34
+ # private (maybe)
35
+ def ok(msg = nil)
36
+ Result.new(true, msg)
40
37
  end
41
- end
42
38
 
43
- def self.ok_if!(evaluator, msg = nil)
44
- if evaluator.is_a? self::Base
45
- return unless evaluator.ok?
46
- evaluator.msg = msg if msg
47
- raise Halt.new(evaluator)
48
- else
49
- raise Halt.new(ok(msg)) if evaluator
39
+ # private (maybe)
40
+ def err(msg = nil)
41
+ Result.new(false, msg)
50
42
  end
51
43
  end
52
-
53
- def self.run
54
- raise 'Block required!' unless block_given?
55
- yield
56
- ok
57
- rescue Halt => e
58
- e.keka
59
- end
60
-
61
-
62
- # private (maybe)
63
- def self.ok(msg = nil)
64
- Base.new(true, msg)
65
- end
66
-
67
- # private (maybe)
68
- def self.err(msg = nil)
69
- Base.new(false, msg)
70
- end
71
-
72
44
  end
@@ -0,0 +1,43 @@
1
+ module Keka
2
+ class Context
3
+
4
+ module Originable
5
+ def rescue_with(err_class, err_msg = nil)
6
+ Context.new.rescue_with(err_class, err_msg)
7
+ end
8
+
9
+ def run(&block)
10
+ Context.new.run(&block)
11
+ end
12
+ end
13
+
14
+ def initialize
15
+ @opts = {
16
+ rescue_exceptions: []
17
+ }
18
+ end
19
+
20
+ def rescue_with(err_class, err_msg = nil)
21
+ opts[:rescue_exceptions] << {
22
+ klass: err_class,
23
+ msg: err_msg
24
+ }
25
+ self
26
+ end
27
+
28
+ def run
29
+ raise 'Block required!' unless block_given?
30
+ yield
31
+ Keka.ok
32
+ rescue Keka::Halt => e
33
+ e.result
34
+ rescue StandardError => e
35
+ raise unless matched = opts[:rescue_exceptions].detect { |setting| e.is_a?(setting[:klass]) }
36
+ Keka.err(matched[:msg])
37
+ end
38
+
39
+ private
40
+ attr_reader :opts
41
+
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ module Keka
2
+ class Halt < StandardError
3
+ attr_reader :result
4
+ def initialize(result)
5
+ @result = result
6
+ super
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Keka
2
+ class Result
3
+ attr_accessor :msg
4
+
5
+ def initialize(is_success, msg)
6
+ @is_success = is_success
7
+ @msg = msg
8
+ end
9
+
10
+ def ok?
11
+ is_success
12
+ end
13
+
14
+ private
15
+ attr_reader :is_success
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Keka
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - zino
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-13 00:00:00.000000000 Z
11
+ date: 2020-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,9 +74,11 @@ extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ".DS_Store"
77
+ - ".circleci/config.yml"
77
78
  - ".gitignore"
78
79
  - ".rspec"
79
- - ".rspec_status"
80
+ - ".ruby-version"
81
+ - CHANGELOG.md
80
82
  - Gemfile
81
83
  - Gemfile.lock
82
84
  - LICENSE.txt
@@ -86,6 +88,9 @@ files:
86
88
  - bin/setup
87
89
  - keka.gemspec
88
90
  - lib/keka.rb
91
+ - lib/keka/context.rb
92
+ - lib/keka/exceptions.rb
93
+ - lib/keka/result.rb
89
94
  - lib/keka/version.rb
90
95
  homepage: https://github.com/zinosama/keka
91
96
  licenses:
@@ -107,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
112
  - !ruby/object:Gem::Version
108
113
  version: '0'
109
114
  requirements: []
110
- rubyforge_project:
111
- rubygems_version: 2.6.14
115
+ rubygems_version: 3.0.2
112
116
  signing_key:
113
117
  specification_version: 4
114
118
  summary: Better handle short-circuit logic, result state, and return message