riker 0.1.0.pre4 → 0.1.0.pre6

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