direct 1.0.0 → 1.1.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: 27fe15c82f220ce786dad7ac7fc5104ed0b8a94c
4
- data.tar.gz: 8f9d2316648c6c4b16d4780f9d4468237ce2583d
2
+ SHA256:
3
+ metadata.gz: fa39232af5f66ca2043ac1b5e258a26e6869b8c012ccaa0661080e89a7644ea8
4
+ data.tar.gz: 2d9ad86998c6903f6c3146258cf278ec0deac829ac96e8ffb85f47967e1e2c4c
5
5
  SHA512:
6
- metadata.gz: f3b80b10949809a4d16dec4b7be942cfb51ca80b80fdae3420bf9ee69ec84ab12d3770ce965fa45269b6e88f16f6dabf242a478aa254ff124c302f220394e8cc
7
- data.tar.gz: 792b7bdf1ea01b24d42f8f28151cc46264efa84115a99f3219b31c494ecbfd9c3c93e848be073dcc7030357acfea47dcfe7161723a81f03cc93d43350728e8e7
6
+ metadata.gz: 4afc48c61d7b189f49b016af2419f54f03a114d5ad5cfcfcfeaa12373e8787d655b651f223e1b9f45b3adef88124c701f452c6077fc3bdc76380d5a3597ed415
7
+ data.tar.gz: bef096a5f6212ca376b919ed1238da53571a9fea95631352686acfe49c6ea8b1b7ec071496dfebbdfd33537c81e7cafefad894eaf6d9e668fbc4cfb03ad3883b
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  Gemfile.lock
10
+ coverage
@@ -1,13 +1,14 @@
1
1
  sudo: false
2
2
  before_install:
3
- - gem install bundler -v 1.16.1
3
+ - gem update --system
4
+ - gem install bundler
4
5
  language: ruby
5
6
  cache: bundler
6
7
  rvm:
7
- - 2.2.9
8
8
  - 2.3.6
9
- - 2.4.3
10
- - 2.5.0
9
+ - 2.4.4
10
+ - 2.5.3
11
+ - 2.6.1
11
12
  - ruby-head
12
13
  - jruby-head
13
14
  env:
@@ -0,0 +1,7 @@
1
+ ## Version 1.1.0
2
+
3
+ Use Direct module to build deferred object internals.
4
+
5
+ ## Version 1.0.0
6
+
7
+ Initial release
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in direct.gemspec
4
3
  gemspec
4
+
5
+ gem 'simplecov', require: false, group: :test
data/README.md CHANGED
@@ -21,13 +21,15 @@ end
21
21
 
22
22
  # Somewhere else
23
23
 
24
- SomeClass.new.direct(:success){|*data|
24
+ SomeClass.new.direct(:success){|something, *data|
25
25
  STDOUT.puts data
26
- }.direct(:failure){|*errors|
26
+ }.direct(:failure){|something, *errors|
27
27
  STDERR.puts errors
28
28
  }.save
29
29
  ```
30
30
 
31
+ Your blocks will always receive the object itself as the first argument.
32
+
31
33
  ## Why?
32
34
 
33
35
  You could easily write code that says `if` this `else` that.
@@ -63,7 +65,7 @@ if something.save!
63
65
  puts "yay! #{something}"
64
66
  elsif something.valid? && !something.persisted?
65
67
  puts "it sort of worked"
66
- elseif !something.valid? || something.need_some_other_thing_set?
68
+ elsif !something.valid? || something.need_some_other_thing_set?
67
69
  puts "an alternative to it not working"
68
70
  else
69
71
  puts "boo! #{something}: #{something.errors}"
@@ -77,13 +79,13 @@ Instead, we can name these scenarios and allow the object to handle them; we
77
79
  merely provide the block of code to execute:
78
80
 
79
81
  ```ruby
80
- Something.new.direct(:success){|the_object|
81
- puts "yay! #{the_object}"
82
- }.direct(:failure){ |the_object, errors|
83
- puts "boo! #{the_object}: #{errors}"
84
- }.direct(:other_scenario){|the_object|
85
- puts "here's what happened and what to do..."
86
- }
82
+ Something.new.direct(:success){ |obj|
83
+ puts "yay! #{obj}"
84
+ }.direct(:failure){ |obj, errors|
85
+ puts "boo! #{obj}: #{errors}"
86
+ }.direct(:other_scenario){ |obj|
87
+ puts "here's what happened and what to do..."
88
+ }
87
89
  ```
88
90
 
89
91
  _Inside_ of the object is where we can handle these named scenarios. If the
@@ -23,7 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency "concurrent-ruby", ">= 1.0"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.16"
27
26
  spec.add_development_dependency "rake", "~> 12.3"
28
27
  spec.add_development_dependency "minitest", "~> 5.11"
29
28
  end
@@ -1,9 +1,30 @@
1
1
  require "direct/version"
2
- require "concurrent"
2
+ require "direct/executable"
3
+ require "direct/group"
3
4
 
4
5
  # Include this module in your classes to provide a way for
5
6
  # your objects to handle named scenarios with blocks of code.
6
7
  module Direct
8
+ class MissingProcedure < StandardError; end
9
+
10
+ # Wrap a block of code to return an object for handling
11
+ # success or failure.
12
+ #
13
+ # Example:
14
+ #
15
+ # def do_it
16
+ # Direct.defer{
17
+ # [true, false].sample
18
+ # }
19
+ # end
20
+ # do_it.
21
+ # success{|result| puts "it worked!" }.
22
+ # failure{|result| puts "it failed!" }
23
+ #
24
+ def self.defer(&block)
25
+ Executable.new(&block)
26
+ end
27
+
7
28
  # Tell the object what to do in a given scenario.
8
29
  #
9
30
  # object.direct(:success){|obj| puts "it worked!" }
@@ -11,16 +32,19 @@ module Direct
11
32
  #
12
33
  # You may also chain calls to this method
13
34
  #
14
- # object.direct(:success){ |obj|
35
+ # object.direct(:success){ |obj|
15
36
  # puts "it worked!"
16
37
  # }.direct(:failure){ |obj|
17
38
  # puts "it failed!"
18
39
  # }.do_it
19
- #
20
- def direct(key, &block)
21
- __direct_store(key, block)
40
+ #
41
+ # Your blocks will always receive the object itself as the first argument.
42
+ #
43
+ def direct(key, callable=nil, &block)
44
+ __directions.store(key, callable || block)
22
45
  self
23
46
  end
47
+ alias_method :when, :direct
24
48
 
25
49
  # Perform the named block of code
26
50
  #
@@ -33,21 +57,16 @@ module Direct
33
57
  #
34
58
  # This will raise an error if the provided key is not found
35
59
  def as_directed(key, *args)
36
- __direct_store_fetch(key).each do |block|
60
+ __directions.fetch(key).map do |block|
37
61
  block.call(self, *args)
38
62
  end
63
+ rescue KeyError
64
+ raise MissingProcedure, "Procedure for :#{key} was reached but not specified."
39
65
  end
40
66
 
41
67
  private
42
68
 
43
- def __direct_store(key, block)
44
- @__direct_store ||= Concurrent::Map.new
45
- @__direct_store.put_if_absent(key, Concurrent::Array.new)
46
- @__direct_store.fetch(key) << block
47
- @__direct_store
48
- end
49
-
50
- def __direct_store_fetch(key)
51
- @__direct_store.fetch(key)
69
+ def __directions
70
+ @__directions ||= Direct::Group.new
52
71
  end
53
72
  end
@@ -0,0 +1,91 @@
1
+ module Direct
2
+ class Executable
3
+ include Direct
4
+
5
+ # It is intended that you initialize objects via Direct.defer
6
+ # and not directly initializing this class.
7
+ #
8
+ # You may initialize this class and provide an object which
9
+ # responds to "call" or a block to execute.
10
+ #
11
+ # Example:
12
+ #
13
+ # Direct.defer do
14
+ # puts "see ya later!"
15
+ # end
16
+ #
17
+ # Direct.defer(->{ "call me, maybe" })
18
+ #
19
+ def initialize(callable=nil, &block)
20
+ @execution = callable || block
21
+ @exception_classes = [StandardError]
22
+ end
23
+ attr_reader :execution, :exception_classes
24
+
25
+ # Tell the object what to do for a success path
26
+ #
27
+ # Returns itself
28
+ #
29
+ def success(callable=nil, &block)
30
+ direct(:success, (callable || block))
31
+ self
32
+ end
33
+
34
+ # Tell the object what to do for a failure path
35
+ #
36
+ # Returns itself
37
+ #
38
+ def failure(callable=nil, &block)
39
+ direct(:failure, (callable || block))
40
+ self
41
+ end
42
+
43
+ # Tell the object what to do for an exception path.
44
+ #
45
+ # You may optionally provide a list of modules rescued by
46
+ # the value method in the case of an exception.
47
+ #
48
+ # Returns itself
49
+ #
50
+ # Example:
51
+ #
52
+ # Direct.defer {
53
+ # # something...
54
+ # }.exception(NoMethodError) { |deferred, exception|
55
+ # ExceptionNotifier.notify(exception)
56
+ # }
57
+ #
58
+ def exception(*classes, &block)
59
+ unless classes.empty?
60
+ @exception_classes = classes
61
+ end
62
+ direct(:exception, block)
63
+ self
64
+ end
65
+
66
+ def run_exception_block(exception)
67
+ if __directions.key?(:exception)
68
+ as_directed(:exception, exception)
69
+ else
70
+ as_directed(:failure, exception)
71
+ end
72
+ end
73
+ private :run_exception_block
74
+
75
+ # Return the value of the success or failure path
76
+ # and rescue from StandardError or from the modules
77
+ # provided to the exception path.
78
+ #
79
+ def value
80
+ result = execution.()
81
+ if result
82
+ as_directed(:success, result)
83
+ else
84
+ as_directed(:failure, result)
85
+ end
86
+ rescue *exception_classes => exception
87
+ run_exception_block(exception)
88
+ end
89
+ alias execute value
90
+ end
91
+ end
@@ -0,0 +1,26 @@
1
+ require 'concurrent'
2
+ module Direct
3
+ class Group
4
+ def initialize
5
+ @map = Concurrent::Map.new{|collection, key|
6
+ collection.put(key, Concurrent::Array.new)
7
+ }
8
+ end
9
+
10
+ attr_reader :map
11
+ private :map
12
+
13
+ def store(key, callable=nil, &block)
14
+ map[key] << (callable || block)
15
+ self
16
+ end
17
+
18
+ def fetch(key)
19
+ map.fetch(key)
20
+ end
21
+
22
+ def key?(key)
23
+ map.key?(key)
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Direct
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  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: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-22 00:00:00.000000000 Z
11
+ date: 2019-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.16'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.16'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +61,7 @@ extra_rdoc_files: []
75
61
  files:
76
62
  - ".gitignore"
77
63
  - ".travis.yml"
64
+ - CHANGELOG.md
78
65
  - CODE_OF_CONDUCT.md
79
66
  - Gemfile
80
67
  - LICENSE.txt
@@ -84,6 +71,8 @@ files:
84
71
  - bin/setup
85
72
  - direct.gemspec
86
73
  - lib/direct.rb
74
+ - lib/direct/executable.rb
75
+ - lib/direct/group.rb
87
76
  - lib/direct/version.rb
88
77
  homepage: https://github.com/saturnflyer/direct
89
78
  licenses:
@@ -104,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
93
  - !ruby/object:Gem::Version
105
94
  version: '0'
106
95
  requirements: []
107
- rubyforge_project:
108
- rubygems_version: 2.5.2.2
96
+ rubygems_version: 3.0.2
109
97
  signing_key:
110
98
  specification_version: 4
111
99
  summary: Direct objects to perform arbitrary blocks by name