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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9ab8741425fa1f9095c3eebf35e5a613cfda2838
4
- data.tar.gz: ae13f53731aad90ae41f1021cfdabe15b0757a0e
2
+ SHA256:
3
+ metadata.gz: b09d224e7ec0f4d9b2f7c3b4e15a87a2f28afb4447391172b8cb7c400d9d3a1f
4
+ data.tar.gz: bf5866603824cb3ee5702476c04759bee58a263606265642dacd92f7b89f5abe
5
5
  SHA512:
6
- metadata.gz: 49e945ea25eb6e058fb1636cc6dabaf83c88cfe25ae5f8ce7bf133e495dfdc428af0162b40af08d25ace04f41cc259b4f1b552f91d013f0a30e36b0ab8fb1519
7
- data.tar.gz: 5b8e3f2ba24641cedcc8666d089dd6ff127b65e0f66077862bc3685bb7ed4839cbcca10f4dfd6bbb17e4f2be32a3af12ad260dbfb6ffaad2090a33adb19a0814
6
+ metadata.gz: f71376313ee4ebe4409a16a1b2bfe394a6b7c847e6ca3c93e633614f36adc8a7845cf8a0191365e03da77c65e3a7c413e93e771d5e811d1ef4b6c3e0657db866
7
+ data.tar.gz: c1f28ac5099779f02b1d57712d9dabd27df43be73ba1bd7032ff1d2d1098683f3170da39abf1ea07030f54948f77dae914958880cacc8cd508fb91c6f6a05a1d
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ *.gem
@@ -0,0 +1,5 @@
1
+ # 0.3.0 / 2019-09-06
2
+ * [FEATURE] Add success/failure callbacks
3
+
4
+ # 0.2.0 / 2018-08-11
5
+ * [FEATURE] Add initialize_with
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
- attr_reader :number_1, :number_2
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/ThalamusAI/mandate.
117
+ Bug reports and pull requests are welcome on GitHub at https://github.com/iHiD/mandate.
@@ -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
- new(*args).call
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Mandate
2
- VERSION = "0.1.0"
2
+ VERSION = "0.4.0.beta.1"
3
3
  end
@@ -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/thalamusai/mandate"
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.15"
25
- spec.add_development_dependency "rake", "~> 10.0"
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.1.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: 2017-10-13 00:00:00.000000000 Z
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.15'
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.15'
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: '10.0'
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: '10.0'
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/thalamusai/mandate
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: '0'
96
+ version: 1.3.1
93
97
  requirements: []
94
- rubyforge_project:
95
- rubygems_version: 2.6.13
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: