riker 0.1.0.pre4 → 0.1.0.pre6

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
2
  SHA256:
3
- metadata.gz: e87101245bca559270ab4ae68b854ddedcf0bcd3a946bdae50571ddb9717b074
4
- data.tar.gz: 702df1dedeacc6dd92dda5a9e90f0640fb1763d9c766e613c4e9669727cae002
3
+ metadata.gz: bd22e31d55bf8c4144736d6b657463e2550b8a602711adfcc4e8339a164d16c6
4
+ data.tar.gz: 83b5819f498d4f86f89531f81df7ca845540b108a5cac03274a0fc9d9f0b1ede
5
5
  SHA512:
6
- metadata.gz: 4fa7e7eef30b47313061ed59cf958b7fb94ca4db2ea461ca94485b9253a3b52223734729ef51fe97bb33456403731aa68281255486aef21218625db708b06609
7
- data.tar.gz: 7c24626c3b722677bd57cb5f83fd092e042b2b06fa170b7edc7fa1e18e2c1eb2cb06cd871bcabfd0cba06046502e9a47eb112f2882c40ee16daabceeac5c9514
6
+ metadata.gz: 7777cf030f8bf79ceaabd4da1a826b32be8cfcc8be0f32b262d1219839dd1268d24596ad3d83320d5eb6da2f15eb9dd31a870ef3f3d12eea53eec61f8bd27982
7
+ data.tar.gz: 818646ea533fefd5fe79580127585ed365af10352ee0f467aa84017a967a6afcdb0ed639f3933fc6c371bd0535b57c8d156b9b6d5066f32ea168e2372ed9bfbe
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in riker.gemspec
6
6
  gemspec
7
7
 
8
+ gem 'pry', '~> 0.14'
8
9
  gem 'rake', '~> 13.0'
9
10
  gem 'rspec', '~> 3.0'
10
11
  gem 'rubocop'
data/Gemfile.lock CHANGED
@@ -1,17 +1,22 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- riker (0.1.0.pre4)
4
+ riker (0.1.0.pre5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
+ coderay (1.1.3)
10
11
  diff-lcs (1.5.0)
11
12
  json (2.6.2)
13
+ method_source (1.0.0)
12
14
  parallel (1.22.1)
13
15
  parser (3.1.2.1)
14
16
  ast (~> 2.4.1)
17
+ pry (0.14.1)
18
+ coderay (~> 1.1)
19
+ method_source (~> 1.0)
15
20
  rainbow (3.1.1)
16
21
  rake (13.0.6)
17
22
  regexp_parser (2.5.0)
@@ -49,6 +54,7 @@ PLATFORMS
49
54
  x86_64-linux
50
55
 
51
56
  DEPENDENCIES
57
+ pry (~> 0.14)
52
58
  rake (~> 13.0)
53
59
  riker!
54
60
  rspec (~> 3.0)
data/README.md CHANGED
@@ -12,7 +12,7 @@ High-Performance, Dependency-Free Command Pattern For Ruby
12
12
  ### In your gemfile:
13
13
 
14
14
  ```ruby
15
- gem 'riker', '0.1.0.pre4'
15
+ gem 'riker', '0.1.0.pre6'
16
16
  ```
17
17
 
18
18
  ### In your code:
@@ -26,6 +26,11 @@ class SimpleGreeting
26
26
  param :punctuation, default: '.'
27
27
 
28
28
  execute do
29
+ if first_name == 'Voldemort'
30
+ errors.add(:first_name, 'He who shall not be named!')
31
+ return
32
+ end
33
+
29
34
  return "Hello #{first_name}#{punctuation}" if last_name.nil?
30
35
 
31
36
  "Hello #{first_name} #{last_name}#{punctuation}"
@@ -44,6 +49,24 @@ SimpleGreeting.run!(first_name: 'Will', last_name: 'Riker')
44
49
 
45
50
  SimpleGreeting.run!(first_name: 'Will', last_name: 'Riker', punctuation: '!')
46
51
  # => "Hello Will Riker!"
52
+
53
+ SimpleGreeting.run!(first_name: 'Voldemort')
54
+ # => Riker::Outcome::ExecutionError => e
55
+ # => e.errors.messages == ['He who shall not be named!']
56
+
57
+ outcome = SimpleGreeting.run(first_name: 'Will')
58
+ outcome.valid?
59
+ # => true
60
+ outcome.result
61
+ # => "Hello Will."
62
+
63
+ outcome = SimpleGreeting.run(first_name: 'Voldemort')
64
+ outcome.invalid?
65
+ # => true
66
+ outcome.result
67
+ # => nil
68
+ outcome.errors.messages
69
+ # => ['He who shall not be named!']
47
70
  ```
48
71
 
49
72
  ## Default Procs
@@ -72,3 +95,39 @@ CaptainsLog.run!(message: "The Borg are attacking!")
72
95
  CaptainsLog.run(message: "We've traveled back in time!", stardate: 42.1337)
73
96
  # => "Captain's Log; Stardate: 42.1337\n\nWe've traveled back in time!"
74
97
  ```
98
+
99
+ ## Measurement Code
100
+
101
+ Sometimes you'll want to do some logic around your commands to record
102
+ their performance, number of calls, etc. Rike allows for this with `around`.
103
+ The result of your measurement code in no way effects the result from
104
+ the command.
105
+
106
+ ```ruby
107
+ module SensorArray
108
+ class << self
109
+ # the class and args of the command are provided
110
+ def deep_scan(klass, args)
111
+ # anything before code runs
112
+
113
+ # code runs here
114
+ yield
115
+
116
+ # anything after you want
117
+ end
118
+ end
119
+ end
120
+
121
+ class CheckWarpDrive
122
+ extend Riker
123
+
124
+ param :stardate
125
+ param :engineer
126
+
127
+ around &SensorArray.method(:deep_scan)
128
+
129
+ execute do
130
+ "WarpDrive checked by #{engineer} on #{stardate}"
131
+ end
132
+ end
133
+ ```
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riker
4
+ class Command
5
+ # Fallible Methods
6
+ #
7
+ # Every command has fallible functionality. This is
8
+ # how you can convey something has gone wrong to the
9
+ # caller of your command.
10
+ #
11
+ module FallibleMethods
12
+ # @return [Riker::Outcome::Errors]
13
+ def errors
14
+ @errors ||= Riker::Outcome::Errors.new
15
+ end
16
+
17
+ # @return [Boolean]
18
+ def errored?
19
+ defined?(@errors) && @errors.any?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'run_bang_function'
4
4
  require_relative 'initialize_function'
5
+ require_relative 'run_function'
5
6
 
6
7
  module Riker
7
8
  class Command
@@ -13,9 +14,14 @@ module Riker
13
14
  class FunctionWriter
14
15
  DEFAULT_FUNCTIONS = [
15
16
  RunBangFunction,
17
+ RunFunction,
16
18
  InitializeFunction
17
19
  ].freeze
18
20
 
21
+ INSTANCE_METHOD_MODULES = [
22
+ FallibleMethods
23
+ ].freeze
24
+
19
25
  # @return [Riker::Command]
20
26
  attr_reader :command
21
27
 
@@ -34,6 +40,7 @@ module Riker
34
40
  define_default_setters!(klass)
35
41
  define_attr_readers!(klass)
36
42
  write_functions!(klass)
43
+ include_instance_methods!(klass)
37
44
  end
38
45
 
39
46
  private
@@ -57,6 +64,13 @@ module Riker
57
64
  param.default.build_default_function!(klass)
58
65
  end
59
66
  end
67
+
68
+ # @param klass [Class]
69
+ def include_instance_methods!(klass)
70
+ INSTANCE_METHOD_MODULES.each do |mod|
71
+ klass.include(mod)
72
+ end
73
+ end
60
74
  end
61
75
  end
62
76
  end
@@ -12,6 +12,11 @@ module Riker
12
12
  include Enumerable
13
13
  class ParamNameTaken < ::Riker::Error; end
14
14
  class InvalidParamName < ::Riker::Error; end
15
+ class ReservedAttributeName < ::Riker::Error; end
16
+
17
+ RESERVED_ATTR_NAMES = %i[
18
+ errors
19
+ ].to_set.freeze
15
20
 
16
21
  def initialize
17
22
  # @var [Hash<Symbol, Parameter>]
@@ -47,6 +52,7 @@ module Riker
47
52
 
48
53
  def validate_name!(name)
49
54
  raise InvalidParamName unless name.is_a?(Symbol)
55
+ raise ReservedAttributeName if RESERVED_ATTR_NAMES.include?(name)
50
56
  raise ParamNameTaken if @params.key?(name)
51
57
  end
52
58
  end
@@ -14,11 +14,43 @@ module Riker
14
14
 
15
15
  # @return [Riker::Command::FunctionDetails]
16
16
  def details
17
+ if command.around_block
18
+ with_around_function_block
19
+ else
20
+ without_around_block_function
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # @return [Riker::Command::FunctionDetails]
27
+ def without_around_block_function
28
+ FunctionDetails.new(<<~RUBY, __FILE__, __LINE__ + 1)
29
+ def self.run!(**arguments) # def self.run!(**arguments)
30
+ command = new(**arguments) # command = new(**arguments)
31
+ result = command.execute # result = command.execute
32
+ if command.errored? # if command.errored?
33
+ command.errors.raise! # command.errors.raise!
34
+ end # end
35
+ result # result
36
+ end # end
37
+ RUBY
38
+ end
39
+
40
+ # @return [Riker::Command::FunctionDetails]
41
+ def with_around_function_block
17
42
  FunctionDetails.new(<<~RUBY, __FILE__, __LINE__ + 1)
18
- def self.run!(**arguments) # def initialize(**arguments)
19
- command = new(**arguments) # command = new(**arguments)
20
- command.execute # command.execute
21
- end # end
43
+ def self.run!(**arguments) # def self.run!(**arguments)
44
+ result = nil # result = nil
45
+ self.command.around_block.call(self, arguments) do # self.command.around_block.call(klass, arguments) do
46
+ command = new(**arguments) # command = new(**arguments)
47
+ result = command.execute # result = command.execute
48
+ if command.errored? # if command.errored?
49
+ command.errors.raise! # command.errors.raise!
50
+ end # end
51
+ end # end
52
+ result # result
53
+ end # end
22
54
  RUBY
23
55
  end
24
56
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riker
4
+ class Command
5
+ # Run!
6
+ #
7
+ # Represents the `run!` static method for your command
8
+ #
9
+ class RunFunction < Function
10
+ # @return [Symbol]
11
+ def name
12
+ :run
13
+ end
14
+
15
+ # @return [Riker::Command::FunctionDetails]
16
+ def details
17
+ if command.around_block
18
+ with_around_block_function
19
+ else
20
+ without_around_block_function
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def without_around_block_function
27
+ FunctionDetails.new(<<~RUBY, __FILE__, __LINE__ + 1)
28
+ def self.run(**arguments) # def self.run!(**arguments)
29
+ command = new(**arguments) # command = new(**arguments)
30
+ result = command.execute # result = command.execute
31
+ if command.errored? # if command.errored?
32
+ Riker::Outcome.invalid(command.errors) # Riker::Outcome.invalid(command.errors)
33
+ else # else
34
+ Riker::Outcome.valid(result) # Riker::Outcome.valid(result)
35
+ end # end
36
+ end # end
37
+ RUBY
38
+ end
39
+
40
+ def with_around_block_function
41
+ FunctionDetails.new(<<~RUBY, __FILE__, __LINE__ + 1)
42
+ def self.run(**arguments) # def self.run!(**arguments)
43
+ outcome = nil # outcome = nil
44
+ self.command.around_block.call(self, arguments) do # self.command.around_block.call(self, arguments) do
45
+ command = new(**arguments) # command = new(**arguments)
46
+ result = command.execute # result = command.execute
47
+ outcome = if command.errored? # outcome = if command.errored?
48
+ Riker::Outcome.invalid(command.errors) # Riker::Outcome.invalid(command.errors)
49
+ else # else
50
+ Riker::Outcome.valid(result) # Riker::Outcome.valid(result)
51
+ end # end
52
+ end # end
53
+ outcome # outcome
54
+ end # end
55
+ RUBY
56
+ end
57
+ end
58
+ end
59
+ end
data/lib/riker/command.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'command/parameters'
4
+ require_relative 'command/fallible_methods'
4
5
  require_relative 'command/function'
5
6
  require_relative 'command/function_details'
6
7
  require_relative 'command/function_writer'
@@ -21,6 +22,9 @@ module Riker
21
22
  # @return [Proc, nil]
22
23
  attr_accessor :execute_block
23
24
 
25
+ # @return [Proc, nil]
26
+ attr_accessor :around_block
27
+
24
28
  def initialize
25
29
  @parameters = Parameters.new
26
30
  @function_writer = FunctionWriter.new(self)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riker
4
+ class Outcome
5
+ # Outcome Errors
6
+ #
7
+ # A wrapper to keep track of and report on errors
8
+ # that happened during the execution of a command.
9
+ #
10
+ class Errors
11
+ # @!method any?
12
+ # @return [Boolean]
13
+ # @!method none?
14
+ # @return [Boolean]
15
+ extend Forwardable
16
+ def_delegators :@errors, :any?, :none?
17
+
18
+ def initialize
19
+ @errors = Hash.new { |hash, key| hash[key] = [] }
20
+ end
21
+
22
+ # @param key [Symbol]
23
+ # @param error [String]
24
+ # @return [void]
25
+ def add(key, error)
26
+ @errors[key] << error
27
+
28
+ nil
29
+ end
30
+
31
+ # @return [Array<String>]
32
+ def messages
33
+ @errors.values.flatten!
34
+ end
35
+
36
+ # @raise [Riker::ExecutionError]
37
+ def raise!
38
+ raise as_execution_error
39
+ end
40
+
41
+ private
42
+
43
+ def as_execution_error
44
+ Riker::Outcome::ExecutionError.new(self)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riker
4
+ class Outcome
5
+ # Execution Error
6
+ #
7
+ # This exception is raised when a problem has happened
8
+ # with your command. It is the result normall of having
9
+ # errors.
10
+ #
11
+ # @see Riker::Command::FallibleMethods
12
+ #
13
+ class ExecutionError < Error
14
+ # @return [Riker::Outcome::Errors]
15
+ attr_reader :errors
16
+
17
+ # @param errors [Riker::Outcome::Errors]
18
+ def initialize(errors)
19
+ super()
20
+ @errors = errors
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'outcome/errors'
4
+ require_relative 'outcome/execution_error'
5
+
6
+ module Riker
7
+ # Wrapped Outcome of a Command
8
+ #
9
+ # Commands may be fallible; and in that case
10
+ # they return an outcome that will either detail
11
+ # the errors that came up during execution or the
12
+ # expected data if it was success.
13
+ #
14
+ class Outcome
15
+ # @return [Object]
16
+ attr_reader :result
17
+
18
+ class << self
19
+ # @param result [Object]
20
+ # @return [Riker::Outcome]
21
+ def valid(result)
22
+ new(:valid, result)
23
+ end
24
+
25
+ def invalid(errors)
26
+ new(:invalid, errors)
27
+ end
28
+
29
+ private :new
30
+ end
31
+
32
+ # @param state [:valid, :invalid]
33
+ # @data [Object, Riker::Outcome::Errors]
34
+ def initialize(state, data)
35
+ if state == :valid
36
+ @result = data
37
+ else
38
+ @errors = data
39
+ end
40
+ end
41
+
42
+ # @return [Boolean]
43
+ def valid?
44
+ return true unless defined?(@errors)
45
+
46
+ @errors.none?
47
+ end
48
+
49
+ # @return [Boolean]
50
+ def invalid?
51
+ return false unless defined?(@errors)
52
+
53
+ @errors.any?
54
+ end
55
+
56
+ # @return [Riker::Outcome::Errors]
57
+ def errors
58
+ @errors ||= Errors.new
59
+ end
60
+ end
61
+ end
data/lib/riker/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Riker
4
- VERSION = '0.1.0.pre4'
4
+ VERSION = '0.1.0.pre6'
5
5
  end
data/lib/riker.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
4
+ require 'set'
5
+
3
6
  require_relative 'riker/version'
4
7
  require_relative 'riker/error'
5
8
  require_relative 'riker/command'
6
9
  require_relative 'riker/parameter'
10
+ require_relative 'riker/outcome'
7
11
 
8
12
  # The Commander of the USS Enterprise
9
13
  module Riker
@@ -27,4 +31,11 @@ module Riker
27
31
  command.execute_block = block
28
32
  command.function_writer.write!(self)
29
33
  end
34
+
35
+ # @block the logic to run around a command
36
+ def around(&block)
37
+ raise Error, "around block already called for #{self}!" if command.around_block
38
+
39
+ command.around_block = block
40
+ end
30
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre4
4
+ version: 0.1.0.pre6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Falk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-07 00:00:00.000000000 Z
11
+ date: 2022-11-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: High-Performance, Dependency-Free Command Pattern For Ruby
14
14
  email:
@@ -29,13 +29,18 @@ files:
29
29
  - bin/setup
30
30
  - lib/riker.rb
31
31
  - lib/riker/command.rb
32
+ - lib/riker/command/fallible_methods.rb
32
33
  - lib/riker/command/function.rb
33
34
  - lib/riker/command/function_details.rb
34
35
  - lib/riker/command/function_writer.rb
35
36
  - lib/riker/command/initialize_function.rb
36
37
  - lib/riker/command/parameters.rb
37
38
  - lib/riker/command/run_bang_function.rb
39
+ - lib/riker/command/run_function.rb
38
40
  - lib/riker/error.rb
41
+ - lib/riker/outcome.rb
42
+ - lib/riker/outcome/errors.rb
43
+ - lib/riker/outcome/execution_error.rb
39
44
  - lib/riker/parameter.rb
40
45
  - lib/riker/parameter/default_value.rb
41
46
  - lib/riker/version.rb