mandate 0.1.0 → 0.4.0.beta.1
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 +5 -5
- data/.gitignore +2 -0
- data/CHANGELOG.md +5 -0
- data/LICENCE +19 -0
- data/README.md +64 -6
- data/lib/mandate.rb +3 -0
- data/lib/mandate/call_injector.rb +13 -1
- data/lib/mandate/callbacks.rb +91 -0
- data/lib/mandate/initializer_injector.rb +55 -0
- data/lib/mandate/memoize.rb +22 -5
- data/lib/mandate/version.rb +1 -1
- data/mandate.gemspec +3 -3
- metadata +17 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b09d224e7ec0f4d9b2f7c3b4e15a87a2f28afb4447391172b8cb7c400d9d3a1f
|
4
|
+
data.tar.gz: bf5866603824cb3ee5702476c04759bee58a263606265642dacd92f7b89f5abe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f71376313ee4ebe4409a16a1b2bfe394a6b7c847e6ca3c93e633614f36adc8a7845cf8a0191365e03da77c65e3a7c413e93e771d5e811d1ef4b6c3e0657db866
|
7
|
+
data.tar.gz: c1f28ac5099779f02b1d57712d9dabd27df43be73ba1bd7032ff1d2d1098683f3170da39abf1ea07030f54948f77dae914958880cacc8cd508fb91c6f6a05a1d
|
data/CHANGELOG.md
ADDED
data/LICENCE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2007 Thalamus AI Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -25,11 +25,7 @@ Or install it yourself as:
|
|
25
25
|
class Multiplies
|
26
26
|
include Mandate
|
27
27
|
|
28
|
-
|
29
|
-
def initialize(number_1, number_2)
|
30
|
-
@number_1 = number_1
|
31
|
-
@number_2 = number_2
|
32
|
-
end
|
28
|
+
initialize_with :number_1, :number_2
|
33
29
|
|
34
30
|
def call
|
35
31
|
do_the_maths
|
@@ -48,6 +44,68 @@ Multiplies.(20, 3)
|
|
48
44
|
# => 60
|
49
45
|
```
|
50
46
|
|
47
|
+
### `initialize_with`
|
48
|
+
|
49
|
+
The `initialize_with` method creates an initializer and private attr_readers for the specified variables.
|
50
|
+
|
51
|
+
For example `initialize_with :foo, :bar` is the equivalent of:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
def initialize(foo, bar)
|
55
|
+
@foo = foo
|
56
|
+
@bar = bar
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
attr_reader :foo, :bar
|
61
|
+
```
|
62
|
+
|
63
|
+
### Using on_success/on_failure callbacks
|
64
|
+
|
65
|
+
Sometimes it is helpful for the class to return on_success/on_failure callbacks rather than just the resulting value.
|
66
|
+
This can be achieved by including the `Mandate::Callbacks` module as follows:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class Sumer
|
70
|
+
include Mandate
|
71
|
+
include Mandate::Callbacks
|
72
|
+
|
73
|
+
initialize_with :num1, :num2
|
74
|
+
|
75
|
+
def call
|
76
|
+
abort!("num1 must be an Integer") unless num1.is_a?(Integer)
|
77
|
+
abort!("num2 must be an Integer") unless num2.is_a?(Integer)
|
78
|
+
|
79
|
+
num1 + num2
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
res = Sumer.(1,2)
|
84
|
+
res.on_success { |result| p result } # puts 3
|
85
|
+
res.on_failure { |errors| p errors } # Noop
|
86
|
+
res.succeeded? # true
|
87
|
+
res.result # 3
|
88
|
+
res.errors # []
|
89
|
+
|
90
|
+
res = Sumer.("1","2")
|
91
|
+
res.on_success { |result| p result } # Noop
|
92
|
+
res.on_failure { |errors| p errors } # puts ["num1 must be an Integer"]
|
93
|
+
|
94
|
+
res = Sumer.("1","2")
|
95
|
+
res.on_failure { |errors| p errors } # puts ["num1 must be an Integer", "num2 must be an Integer"]
|
96
|
+
res.errors # ["num1 must be an Integer", "num2 must be an Integer"]
|
97
|
+
```
|
98
|
+
|
99
|
+
It is also possible to chain methods, for example:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Sumer.(1,2).
|
103
|
+
on_success { |result| p result }.
|
104
|
+
on_failure { |errors| p errors }
|
105
|
+
```
|
106
|
+
|
107
|
+
The `succeeded?` method is also aliased as `success?`.
|
108
|
+
|
51
109
|
## Development
|
52
110
|
|
53
111
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -56,4 +114,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
56
114
|
|
57
115
|
## Contributing
|
58
116
|
|
59
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
117
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/iHiD/mandate.
|
data/lib/mandate.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require "mandate/version"
|
2
2
|
require "mandate/memoize"
|
3
3
|
require "mandate/call_injector"
|
4
|
+
require "mandate/initializer_injector"
|
5
|
+
require "mandate/callbacks"
|
4
6
|
|
5
7
|
module Mandate
|
6
8
|
def self.included(base)
|
7
9
|
base.extend(Memoize)
|
8
10
|
base.extend(CallInjector)
|
11
|
+
base.extend(InitializerInjector)
|
9
12
|
end
|
10
13
|
end
|
@@ -1,9 +1,21 @@
|
|
1
1
|
module Mandate
|
2
2
|
module CallInjector
|
3
3
|
def self.extended(base)
|
4
|
+
# Defining call allows us to do use the syntax:
|
5
|
+
# Foobar.(some, args)
|
6
|
+
# which internally calls:
|
7
|
+
# Foobar.new(some, args).call()
|
4
8
|
class << base
|
5
9
|
def call(*args)
|
6
|
-
|
10
|
+
# If the last argument is a hash and the last param is a keyword params (signified by
|
11
|
+
# its type being :key, the we should pass the hash in in using the **kwords syntax.
|
12
|
+
# This fixes a deprecation issue in Ruby 2.7.
|
13
|
+
if args.last.is_a?(Hash) &&
|
14
|
+
:key == instance_method(:initialize).parameters.last&.first
|
15
|
+
new(*args[0..-2], **args[-1]).call
|
16
|
+
else
|
17
|
+
new(*args).call
|
18
|
+
end
|
7
19
|
end
|
8
20
|
end
|
9
21
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Mandate
|
2
|
+
module Callbacks
|
3
|
+
class AbortError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class Results
|
7
|
+
attr_reader :result, :errors
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@succeeded = false
|
11
|
+
@errors = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def succeeded!(result)
|
15
|
+
@result = result
|
16
|
+
@succeeded = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_error(error)
|
20
|
+
errors << error
|
21
|
+
end
|
22
|
+
|
23
|
+
def succeeded?
|
24
|
+
!!succeeded
|
25
|
+
end
|
26
|
+
alias_method :success?, :succeeded?
|
27
|
+
|
28
|
+
def on_success(&block)
|
29
|
+
block.call(result) if succeeded?
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_failure(&block)
|
34
|
+
block.call(errors) unless succeeded?
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
attr_reader :succeeded
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
# Override self.call to call the internal call_with_callbacks
|
44
|
+
# function which returns a method with on_success/on_failure callbacks
|
45
|
+
class << base
|
46
|
+
# Remove the existing created by the "include Mandate"
|
47
|
+
remove_method(:call)
|
48
|
+
|
49
|
+
# Define a new call methods which calls the instance call
|
50
|
+
# method but with the added callbacks needed for on_success/on_failure
|
51
|
+
def call(*args)
|
52
|
+
new(*args).call_with_callbacks
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
base.extend(Callbacks)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.extended(base)
|
60
|
+
base.send(:define_method, :call_with_callbacks) do
|
61
|
+
begin
|
62
|
+
# Create results object
|
63
|
+
@__mandate_results = Results.new
|
64
|
+
|
65
|
+
# Run the actual command
|
66
|
+
# If call fails, succeeded! will never get called
|
67
|
+
@__mandate_results.succeeded!(call)
|
68
|
+
rescue AbortError
|
69
|
+
end
|
70
|
+
|
71
|
+
@__mandate_results
|
72
|
+
end
|
73
|
+
|
74
|
+
base.send(:define_method, :add_error!) do |error|
|
75
|
+
@__mandate_results.add_error(error)
|
76
|
+
end
|
77
|
+
base.send(:private, :add_error!)
|
78
|
+
|
79
|
+
base.send(:define_method, :abort!) do |error = nil|
|
80
|
+
add_error!(error) if error
|
81
|
+
raise AbortError
|
82
|
+
end
|
83
|
+
base.send(:private, :abort!)
|
84
|
+
|
85
|
+
base.send(:define_method, :abort_if_errored!) do
|
86
|
+
raise AbortError if @__mandate_results.errors.size > 0
|
87
|
+
end
|
88
|
+
base.send(:private, :abort_if_errored!)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Mandate
|
2
|
+
module InitializerInjector
|
3
|
+
def self.extended(base)
|
4
|
+
class << base
|
5
|
+
def initialize_with(*attrs, **kwattrs)
|
6
|
+
if kwattrs.empty?
|
7
|
+
define_method :initialize do |*args|
|
8
|
+
unless args.length == attrs.length
|
9
|
+
raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected #{attrs.length})")
|
10
|
+
end
|
11
|
+
|
12
|
+
attrs.zip(args).each do |attr,arg|
|
13
|
+
instance_variable_set("@#{attr}", arg)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
else
|
17
|
+
define_method :initialize do |*args, **kwargs|
|
18
|
+
unless args.length == attrs.length
|
19
|
+
raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected #{attrs.length})")
|
20
|
+
end
|
21
|
+
|
22
|
+
attrs.zip(args).each do |attr,arg|
|
23
|
+
instance_variable_set("@#{attr}", arg)
|
24
|
+
end
|
25
|
+
|
26
|
+
kwargs.each do |name,value|
|
27
|
+
if kwattrs.keys.include?(name)
|
28
|
+
instance_variable_set("@#{name}", value)
|
29
|
+
else
|
30
|
+
raise ArgumentError.new("unknown keyword: #{name}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
attrs.each do |attr|
|
37
|
+
define_method attr do instance_variable_get("@#{attr}") end
|
38
|
+
private attr
|
39
|
+
end
|
40
|
+
|
41
|
+
kwattrs.each do |attr,default|
|
42
|
+
define_method attr do
|
43
|
+
if instance_variable_defined?("@#{attr}")
|
44
|
+
instance_variable_get("@#{attr}")
|
45
|
+
else
|
46
|
+
default
|
47
|
+
end
|
48
|
+
end
|
49
|
+
private attr
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/mandate/memoize.rb
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
module Mandate
|
2
2
|
module Memoize
|
3
|
+
|
4
|
+
# This method is called on the line before a
|
5
|
+
# define statement. It puts mandate into memoizing mode
|
3
6
|
def memoize
|
4
7
|
@__mandate_memoizing = true
|
5
8
|
end
|
6
9
|
|
10
|
+
# Intercept a method being added.
|
11
|
+
# Create the method as normal, then if we are in
|
12
|
+
# memoize mode, call out to the memozie function and
|
13
|
+
# reset out of memozing mode.
|
7
14
|
def method_added(method_name)
|
8
15
|
super
|
9
|
-
return unless @__mandate_memoizing
|
10
16
|
|
17
|
+
if instance_variable_defined?("@__mandate_memoizing") && @__mandate_memoizing
|
18
|
+
__mandate_memoize(method_name)
|
19
|
+
@__mandate_memoizing = false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create an anonymous module that defines a method
|
24
|
+
# with the same name as main method being defined.
|
25
|
+
# Add some memoize code to check whether the method
|
26
|
+
# has been previously called or not. If it's not
|
27
|
+
# been then call the underlying method and store the result.
|
28
|
+
#
|
29
|
+
# We then prepend this module so that its method
|
30
|
+
# comes first in the method-lookup chain.
|
31
|
+
def __mandate_memoize(method_name)
|
11
32
|
memoizer = Module.new do
|
12
|
-
p method_name
|
13
33
|
define_method method_name do
|
14
34
|
@__mandate_memoized_results ||= {}
|
15
35
|
|
@@ -20,10 +40,7 @@ module Mandate
|
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
23
|
-
|
24
43
|
prepend memoizer
|
25
|
-
|
26
|
-
@__mandate_memoizing = false
|
27
44
|
end
|
28
45
|
end
|
29
46
|
end
|
data/lib/mandate/version.rb
CHANGED
data/mandate.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
|
13
13
|
spec.summary = %q{A simple command-pattern helper gem for Ruby}
|
14
14
|
spec.description = %q{This Ruby Gem adds functionality for the command pattern in Ruby, and for memoization.}
|
15
|
-
spec.homepage = "https://github.com/
|
15
|
+
spec.homepage = "https://github.com/iHiD/mandate"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
18
|
f.match(%r{^(test|spec|features)/})
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler", "~> 1
|
25
|
-
spec.add_development_dependency "rake", "~>
|
24
|
+
spec.add_development_dependency "bundler", "~> 2.1"
|
25
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
26
26
|
spec.add_development_dependency "minitest", "~> 5.0"
|
27
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mandate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Walker
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '12.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '12.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,21 +62,25 @@ extra_rdoc_files: []
|
|
62
62
|
files:
|
63
63
|
- ".gitignore"
|
64
64
|
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
65
66
|
- Gemfile
|
67
|
+
- LICENCE
|
66
68
|
- README.md
|
67
69
|
- Rakefile
|
68
70
|
- bin/console
|
69
71
|
- bin/setup
|
70
72
|
- lib/mandate.rb
|
71
73
|
- lib/mandate/call_injector.rb
|
74
|
+
- lib/mandate/callbacks.rb
|
75
|
+
- lib/mandate/initializer_injector.rb
|
72
76
|
- lib/mandate/memoize.rb
|
73
77
|
- lib/mandate/version.rb
|
74
78
|
- mandate.gemspec
|
75
|
-
homepage: https://github.com/
|
79
|
+
homepage: https://github.com/iHiD/mandate
|
76
80
|
licenses:
|
77
81
|
- MIT
|
78
82
|
metadata: {}
|
79
|
-
post_install_message:
|
83
|
+
post_install_message:
|
80
84
|
rdoc_options: []
|
81
85
|
require_paths:
|
82
86
|
- lib
|
@@ -87,14 +91,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
91
|
version: '0'
|
88
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
93
|
requirements:
|
90
|
-
- - "
|
94
|
+
- - ">"
|
91
95
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
96
|
+
version: 1.3.1
|
93
97
|
requirements: []
|
94
|
-
|
95
|
-
|
96
|
-
signing_key:
|
98
|
+
rubygems_version: 3.1.2
|
99
|
+
signing_key:
|
97
100
|
specification_version: 4
|
98
101
|
summary: A simple command-pattern helper gem for Ruby
|
99
102
|
test_files: []
|
100
|
-
has_rdoc:
|