direct 2.0.0 → 2.0.1

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: 812ea6d0360b4161fba6c6fcd38d409715900ff08cdd57f3d4cf4df5df2de900
4
- data.tar.gz: b3b95cafabb8381687d8a033f4c14b9d57164b101236c61a4faa960a5b73890b
3
+ metadata.gz: 0c4b78452caed73b8ce6c197b9825690120664cfedf0a695e0b8dee7d3f93e9e
4
+ data.tar.gz: d16639349d3041cc46fd0aa8edf6cc6565e24ff70b97dd275bc6c4dbeba1c853
5
5
  SHA512:
6
- metadata.gz: 737c8f8dfd54bef81cb284c5bf0fceb02b8ff53df4b9fa31231bbd78d1b9f86bcf83f34e60befce7ed87d368843b63e35de73de16a6578aae5f09cc1a60d5f56
7
- data.tar.gz: fffe7ce4459bd5ea399d4103a19ed561955b4e5c241a407c772d4f03669cf9328f108e5fbf704c664dcafd06ccbcdf826b50235e870e7f8522a40f0004ef3e2e
6
+ metadata.gz: 2193d4a0199deb76f94bdcb22fe6042d393a32a0a23581f6957f066d6609ad51e8590436a284fa818a939b3fcd00aa495724d229d9af65c18e9dd86bc0e670ff
7
+ data.tar.gz: cd31472b4a110ceeab0cff5af7700314b71e10f911b12a426491acc94019879d92374cefdc301cc258cf3c5197f097bc9d32ae8e5209569dd7102f26131a6fe8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## Version 2.0.1
2
+
3
+ Introduce an ExceptionHandler to allow for multiple exception blocks
4
+ Drop Ruby 2.6 support
5
+ Fix bug where strict_defer was not accepting callable and object arguments.
6
+ Drop Ruby 2.5 and below
7
+
1
8
  ## Version 2.0.0
2
9
 
3
10
  A bug in deferred execution did not return the success/failure results. Fixes test names that cause a collision and incorrect test scenarios.
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 Jim Gay
3
+ Copyright (c) 2018-2022 Jim Gay
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -34,7 +34,7 @@ SomeClass.new.procedure.success{ |deferred_object, result, object|
34
34
  puts "it worked!"
35
35
  }.failure { |deferred_object, result, object|
36
36
  puts "it failed :-("
37
- }.exception{ |deferred_object, exception, object|
37
+ }.exception { |deferred_object, exception, object|
38
38
  puts "Oh no! An exception was raised!"
39
39
  }.execute
40
40
  ```
@@ -51,6 +51,16 @@ SomeClass.new.procedure.success{ |deferred_object, result, object|
51
51
  }.execute
52
52
  ```
53
53
 
54
+ You can also handle different exceptions with different blocks:
55
+
56
+ ```ruby
57
+ SomeClass.new.procedure.exception(SomeLibrary::SomeSpecialError){ |deferred_object, exception, object|
58
+ puts "Oh no! A Special Error!"
59
+ }.exception(ArgumentError){ |deferred_object, exception, object|
60
+ puts "Oops! The arguments are wrong!"
61
+ }.execute
62
+ ```
63
+
54
64
  The `defer` method uses built-in classes but you can build your own to manage executing named blocks
55
65
 
56
66
  ```ruby
data/Rakefile CHANGED
@@ -7,4 +7,4 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList["test/**/*_test.rb"]
8
8
  end
9
9
 
10
- task :default => :test
10
+ task default: :test
@@ -0,0 +1,31 @@
1
+ module Direct
2
+ # This class monitors exception types with related blocks.
3
+ class ExceptionHandler
4
+ def initialize
5
+ @handlers = {}
6
+ end
7
+
8
+ # All classes, including StandardError, for which this object
9
+ # maintains a block to execute.
10
+ def classes
11
+ [StandardError, @handlers.keys.flatten].flatten
12
+ end
13
+
14
+ # Pass a single or multiple exception classes and the block
15
+ # to be used to handle them.
16
+ def monitor(*classes, &block)
17
+ @handlers[classes.flatten] = block
18
+ end
19
+
20
+ # This will find the first handler given to `monitor` which matches
21
+ # the provided exception's class and will execute it with the
22
+ # deferred object, the exception object, and any given object to the
23
+ # deferred object.
24
+ def call(deferred, exception, object)
25
+ if_none = proc { raise "No handler for this exception: #{exception.class}!" }
26
+ result = @handlers.find(if_none) { |key, val| key.include?(exception.class) }
27
+
28
+ result.last.call(deferred, exception, object)
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,5 @@
1
+ require "direct/exception_handler"
2
+
1
3
  module Direct
2
4
  class Executable
3
5
  include Direct.allow_missing_directions
@@ -40,18 +42,20 @@ module Direct
40
42
  # puts "The #{thing} did something!"
41
43
  # }.execute
42
44
  #
43
- def initialize(callable=nil, object: nil, &block)
44
- @object = object
45
+ def initialize(callable = nil, *args, **kwargs, &block)
46
+ @object = kwargs.delete(:object)
47
+ @args = args
48
+ @kwargs = kwargs
49
+ @exception_handler = kwargs.delete(:exception_handler) || ExceptionHandler.new
45
50
  @execution = callable || block
46
- @exception_classes = [StandardError]
47
51
  end
48
- attr_reader :execution, :exception_classes, :object
52
+ attr_reader :execution, :exception_handler, :object, :args, :kwargs
49
53
 
50
54
  # Tell the object what to do for a success path
51
55
  #
52
56
  # Returns itself
53
57
  #
54
- def success(callable=nil, &block)
58
+ def success(callable = nil, &block)
55
59
  direct(:success, (callable || block))
56
60
  self
57
61
  end
@@ -60,7 +64,7 @@ module Direct
60
64
  #
61
65
  # Returns itself
62
66
  #
63
- def failure(callable=nil, &block)
67
+ def failure(callable = nil, &block)
64
68
  direct(:failure, (callable || block))
65
69
  self
66
70
  end
@@ -81,18 +85,22 @@ module Direct
81
85
  # }
82
86
  #
83
87
  def exception(*classes, &block)
84
- unless classes.empty?
85
- @exception_classes = classes
86
- end
87
- direct(:exception, block)
88
+ classes = [StandardError] if classes.empty?
89
+ exception_handler.monitor(classes, &block)
90
+
91
+ direct(:exception, exception_handler)
88
92
  self
89
93
  end
90
94
 
95
+ def exception_classes
96
+ exception_handler.classes
97
+ end
98
+
91
99
  def run_exception_block(exception)
92
100
  if __directions.key?(:exception)
93
- as_directed(:exception, exception, object)
101
+ as_directed(:exception, exception, object, *args, **kwargs)
94
102
  else
95
- as_directed(:failure, exception, object)
103
+ as_directed(:failure, exception, object, *args, **kwargs)
96
104
  end
97
105
  end
98
106
  private :run_exception_block
@@ -102,15 +110,23 @@ module Direct
102
110
  # provided to the exception path.
103
111
  #
104
112
  def value
105
- result = execution.()
106
- if result
107
- as_directed(:success, result, object) || result
108
- else
109
- as_directed(:failure, result, object) || result
110
- end
113
+ trigger_directions
111
114
  rescue *exception_classes => exception
112
115
  run_exception_block(exception)
113
116
  end
114
- alias execute value
117
+ alias_method :execute, :value
118
+
119
+ def trigger_directions
120
+ result = execution.call
121
+ if result
122
+ as_directed(:success, result, object, *args, **kwargs)
123
+ else
124
+ as_directed(:failure, result, object, *args, **kwargs)
125
+ end || result
126
+ end
127
+ private :trigger_directions
128
+
115
129
  end
130
+
131
+ private_constant :Executable
116
132
  end
data/lib/direct/group.rb CHANGED
@@ -1,16 +1,16 @@
1
- require 'concurrent'
1
+ require "concurrent"
2
2
  module Direct
3
3
  class Group
4
4
  def initialize
5
- @map = Concurrent::Map.new{|collection, key|
6
- collection.put(key, Concurrent::Array.new)
5
+ @map = Concurrent::Map.new { |collection, key|
6
+ collection.put(key, Concurrent::Set.new)
7
7
  }
8
8
  end
9
9
 
10
10
  attr_reader :map
11
11
  private :map
12
12
 
13
- def store(key, callable=nil, &block)
13
+ def store(key, callable = nil, &block)
14
14
  map[key] << (callable || block)
15
15
  self
16
16
  end
@@ -31,4 +31,6 @@ module Direct
31
31
  map.keys.inspect
32
32
  end
33
33
  end
34
+
35
+ private_constant :Group
34
36
  end
@@ -1,5 +1,5 @@
1
1
  module Direct
2
- class StrictExecutable
2
+ class StrictExecutable < Executable
3
3
  include Direct
4
4
 
5
5
  # It is intended that you initialize objects via Direct.strict_defer
@@ -42,77 +42,20 @@ module Direct
42
42
  # puts "#{thing} failed!"
43
43
  # }.execute
44
44
  #
45
- def initialize(callable=nil, object: nil, &block)
46
- @object = object
47
- @execution = callable || block
48
- @exception_classes = [StandardError]
49
- end
50
- attr_reader :execution, :exception_classes, :object
51
-
52
- # Tell the object what to do for a success path
53
- #
54
- # Returns itself
55
- #
56
- def success(callable=nil, &block)
57
- direct(:success, (callable || block))
58
- self
59
- end
60
-
61
- # Tell the object what to do for a failure path
62
- #
63
- # Returns itself
64
- #
65
- def failure(callable=nil, &block)
66
- direct(:failure, (callable || block))
67
- self
68
- end
69
-
70
- # Tell the object what to do for an exception path.
71
- #
72
- # You may optionally provide a list of modules rescued by
73
- # the value method in the case of an exception.
74
- #
75
- # Returns itself
76
- #
77
- # Example:
78
- #
79
- # Direct.strict_defer {
80
- # # something...
81
- # }.exception(NoMethodError) { |deferred, exception, object|
82
- # ExceptionNotifier.notify(exception)
83
- # }
84
- #
85
- def exception(*classes, &block)
86
- unless classes.empty?
87
- @exception_classes = classes
88
- end
89
- direct(:exception, block)
90
- self
91
- end
92
-
93
- def run_exception_block(exception)
94
- if __directions.key?(:exception)
95
- as_directed(:exception, exception, object)
96
- else
97
- as_directed(:failure, exception, object)
98
- end
99
- end
100
- private :run_exception_block
101
45
 
102
- # Return the value of the success or failure path
103
- # and rescue from StandardError or from the modules
104
- # provided to the exception path.
46
+ # Override the behavior of the parent class to *not* fall back to the
47
+ # result.
105
48
  #
106
- def value
107
- result = execution.()
49
+ def trigger_directions
50
+ result = execution.call
108
51
  if result
109
- as_directed(:success, result)
52
+ as_directed(:success, result, object, *args, **kwargs)
110
53
  else
111
- as_directed(:failure, result)
54
+ as_directed(:failure, result, object, *args, **kwargs)
112
55
  end
113
- rescue *exception_classes => exception
114
- run_exception_block(exception)
115
56
  end
116
- alias execute value
57
+ private :trigger_directions
117
58
  end
59
+
60
+ private_constant :StrictExecutable
118
61
  end
@@ -1,3 +1,3 @@
1
1
  module Direct
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
data/lib/direct.rb CHANGED
@@ -52,8 +52,8 @@ module Direct
52
52
  # failure{|result| puts "it failed!" }.
53
53
  # value
54
54
  #
55
- def self.strict_defer(&block)
56
- StrictExecutable.new(&block)
55
+ def self.strict_defer(callable = nil, *args, object: nil, **kwargs, &block)
56
+ StrictExecutable.new(callable, *args, object: object, **kwargs, &block)
57
57
  end
58
58
 
59
59
  # Wrap a block of code to return an object for handling
@@ -68,8 +68,8 @@ module Direct
68
68
  # end
69
69
  # do_it.value
70
70
  #
71
- def self.defer(*args, object: nil, &block)
72
- Executable.new(*args, object: object, &block)
71
+ def self.defer(callable = nil, *args, object: nil, **kwargs, &block)
72
+ Executable.new(callable, *args, object: object, **kwargs, &block)
73
73
  end
74
74
 
75
75
  # Tell the object what to do in a given scenario.
@@ -85,9 +85,9 @@ module Direct
85
85
  # puts "it failed!"
86
86
  # }.do_it
87
87
  #
88
- # Your blocks will always receive the object itself as the first argument.
88
+ # Your blocks will *always* receive the object itself as the first argument.
89
89
  #
90
- def direct(key, callable=nil, &block)
90
+ def direct(key, callable = nil, &block)
91
91
  __directions.store(key, callable || block)
92
92
  self
93
93
  end
@@ -103,10 +103,12 @@ module Direct
103
103
  # end
104
104
  #
105
105
  # This will raise an error if the provided key is not found
106
- def as_directed(key, *args)
106
+ #
107
+ # The current value for self will be sent as the first argument to the block
108
+ def as_directed(key, ...)
107
109
  return if allow_missing_directions? && __directions.empty?
108
110
  __directions.fetch(key).map do |block|
109
- block.call(self, *args)
111
+ block.call(self, ...)
110
112
  end
111
113
  rescue KeyError
112
114
  return if allow_missing_directions?
@@ -120,6 +122,6 @@ module Direct
120
122
  end
121
123
 
122
124
  def __directions
123
- @__directions ||= Direct::Group.new
125
+ @__directions ||= Group.new
124
126
  end
125
127
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: direct
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-09 00:00:00.000000000 Z
11
+ date: 2022-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -31,18 +31,13 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - ".gitignore"
35
- - ".travis.yml"
36
34
  - CHANGELOG.md
37
35
  - CODE_OF_CONDUCT.md
38
- - Gemfile
39
36
  - LICENSE.txt
40
37
  - README.md
41
38
  - Rakefile
42
- - bin/console
43
- - bin/setup
44
- - direct.gemspec
45
39
  - lib/direct.rb
40
+ - lib/direct/exception_handler.rb
46
41
  - lib/direct/executable.rb
47
42
  - lib/direct/group.rb
48
43
  - lib/direct/strict_executable.rb
@@ -59,14 +54,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
54
  requirements:
60
55
  - - ">="
61
56
  - !ruby/object:Gem::Version
62
- version: '0'
57
+ version: '2.7'
63
58
  required_rubygems_version: !ruby/object:Gem::Requirement
64
59
  requirements:
65
60
  - - ">="
66
61
  - !ruby/object:Gem::Version
67
62
  version: '0'
68
63
  requirements: []
69
- rubygems_version: 3.1.2
64
+ rubygems_version: 3.4.1
70
65
  signing_key:
71
66
  specification_version: 4
72
67
  summary: Direct objects to perform arbitrary blocks by name
data/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
- Gemfile.lock
10
- coverage
data/.travis.yml DELETED
@@ -1,28 +0,0 @@
1
- sudo: false
2
- before_install:
3
- - gem update --system
4
- - gem install bundler
5
- language: ruby
6
- cache: bundler
7
- rvm:
8
- - 2.3.6
9
- - 2.4.4
10
- - 2.5.3
11
- - 2.6.1
12
- - ruby-head
13
- - jruby-head
14
- env:
15
- global:
16
- - CC_TEST_REPORTER_ID=3c4cb48bcc4e29bb3292e99b7736c6dd7c13d0f6a908785e164d03666f5070cc
17
- matrix:
18
- allow_failures:
19
- - rvm: ruby-head
20
- - rvm: jruby-head
21
- before_script:
22
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
23
- - chmod +x ./cc-test-reporter
24
- - ./cc-test-reporter before-build
25
- script:
26
- - bundle exec rake
27
- after_script:
28
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec
4
-
5
- gem "rake", "~> 12.3"
6
- gem "minitest", "~> 5.11"
7
- gem "pry-byebug"
8
- gem "simplecov", require: false, group: :test
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "direct"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/direct.gemspec DELETED
@@ -1,25 +0,0 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "direct/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "direct"
8
- spec.version = Direct::VERSION
9
- spec.authors = ["Jim Gay"]
10
- spec.email = ["jim@saturnflyer.com"]
11
-
12
- spec.summary = %q{Direct objects to perform arbitrary blocks by name}
13
- spec.description = %q{Direct objects to perform arbitrary blocks by name}
14
- spec.homepage = "https://github.com/saturnflyer/direct"
15
- spec.license = "MIT"
16
-
17
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
- f.match(%r{^(test|spec|features)/})
19
- end
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
23
-
24
- spec.add_dependency "concurrent-ruby", ">= 1.0"
25
- end