direct 1.0.0 → 1.1.0

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