makwa 0.1.0 → 0.2.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
2
  SHA256:
3
- metadata.gz: 1efddd0368efae3bf02af1759d3923729f39414c2d728c3567aa911ec2bd5892
4
- data.tar.gz: ff81e0decb31353995008f0a4c3d69c14f741d45a30a72fa7015f8149b377ca3
3
+ metadata.gz: 2da52aacefd38c1922e5e8b48277fca8106997a068b682d93698bd9e444da41f
4
+ data.tar.gz: a506c6b8ae75f3d093afdf455b84733f0d0984843561dde099bbbb9ffddc7e91
5
5
  SHA512:
6
- metadata.gz: ca622d29e65ddd191fcaa8dad747e4a7ed7ca1fb3fba11cf2749276f61ab38706e88d36a4ed6d531fcadebc7a28fb9c767932039684bd40b706df081ac37201f
7
- data.tar.gz: f84ceb0ed0e479c2aa18ab58a9ee3504591c3b3df0e444eb4c111aa09c204fdef198f3b49073d297127622e9027b6d8a719a055ddf9aafbc6c81075a59430375
6
+ metadata.gz: 8784e825031765550dce4b56c82aae5a872d403cf14f444cdb0a2afb00fd2603e14f28910a92f3415b60df351820a17f738264eb6bf3bacd050f3ac21ee79c43
7
+ data.tar.gz: ea5dde94eca0a95abda600e4bd8f129dc63413a855cdf3ffb9ee5f15176ee7f1edcd368216265aff272def00ca4795b647f7667bd6bbe58ec3a742ab361274bd
data/.gitignore CHANGED
@@ -2,7 +2,9 @@
2
2
  /.yardoc
3
3
  /_yardoc/
4
4
  /coverage/
5
- /doc/
6
5
  /pkg/
7
6
  /spec/reports/
8
7
  /tmp/
8
+
9
+ Gemfile.lock
10
+ .byebug_history
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2021-10-27
4
+
5
+ - Adds implementation
6
+ - Updates ReturningInteraction to copy errors and values to returned object on invalid inputs
7
+
3
8
  ## [0.1.0] - 2021-09-23
4
9
 
5
10
  - Initial release
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021 Jo Hund
3
+ Copyright (c) 2021 Animikii
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -1,4 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+
5
+ require "rake/testtask"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.pattern = "test/**/*_test.rb"
10
+ t.verbose = false
11
+ end
12
+
13
+ task default: :test
@@ -0,0 +1,14 @@
1
+ # How to release a new version
2
+
3
+ * Make changes to the code
4
+ * Update tests as needed
5
+ * Update CHANGELOG.md
6
+ * Commit changes
7
+ * Prepare new release
8
+ * Bump version via one of
9
+ * `gem bump --tag --version major`
10
+ * `gem bump --tag --version minor`
11
+ * `gem bump --tag --version patch`
12
+ * The bump command will commit the new version and tag the commit.
13
+ * Distribute new release
14
+ * `gem release` - This will push the new release to rubygems.org.
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makwa
4
+ class Interaction < ::ActiveInteraction::Base
5
+ class Interrupt < Object.const_get("::ActiveInteraction::Interrupt")
6
+ end
7
+
8
+ #
9
+ # Safely checking for errors
10
+ #
11
+
12
+ # Use this instead of `outcome.invalid?` (which is destructive and clears errors)
13
+ delegate :any?, to: :errors, prefix: true # def errors_any?
14
+ # Use this instead of `outcome.valid?` (which is destructive and clears errors)
15
+ delegate :empty?, to: :errors, prefix: true # def errors_empty?
16
+
17
+ #
18
+ # Halting of execution
19
+ #
20
+
21
+ # Exits early if there are any errors.
22
+ def return_if_errors!
23
+ raise(Interrupt, errors) if errors_any?
24
+ end
25
+
26
+ #
27
+ # Logging interaction execution
28
+ #
29
+
30
+ # Log execution of interaction, caller, and inputs
31
+ set_callback :type_check, :before, ->(interaction) {
32
+ debug("Executing interaction #{interaction.class.name} #{interaction.id_marker}")
33
+ calling_interaction = interaction.calling_interaction
34
+ debug(" ↳ called from #{calling_interaction} #{interaction.id_marker}") if calling_interaction.present?
35
+ # The next two lines offer two ways of printing inputs: Either truncated, or full. Adjust as needed.
36
+ # truncated_inputs = interaction.inputs.inspect.truncate_in_the_middle(2000, omission: "\n... [inputs truncated] ...\n")
37
+ truncated_inputs = interaction.inputs.inspect
38
+ debug(" ↳ inputs: #{truncated_inputs} #{interaction.id_marker}")
39
+ }
40
+
41
+ # Log interaction's outcome and errors if any.
42
+ set_callback :execute, :after, ->(interaction) {
43
+ if interaction.errors_empty?
44
+ debug(" ↳ outcome: succeeded (id##{interaction.object_id})")
45
+ else
46
+ debug(" ↳ outcome: failed (id##{interaction.object_id})")
47
+ debug(" ↳ errors: #{interaction.errors.details} (id##{interaction.object_id})")
48
+ end
49
+ }
50
+
51
+ # @return [Array<String>] the callstack containing interactions only, starting with the immediate caller.
52
+ def calling_interactions
53
+ @calling_interactions ||= caller.find_all { |e|
54
+ e.index("/app/interactions/") && !e.index(__FILE__) && !e.index("/returning_interaction.rb")
55
+ }
56
+ end
57
+
58
+ # @return [String] the backtrace entry for the immediately calling interaction (first item in calling_interactions).
59
+ def calling_interaction
60
+ @calling_interaction ||= calling_interactions.first&.split("/interactions/")&.last || ""
61
+ end
62
+
63
+ # The standard method for all logging output. Turn this on for detailed interaction logging.
64
+ def debug(txt)
65
+ # puts indent + txt
66
+ end
67
+
68
+ # @return [String] a marker that identifies an interaction instance by its Ruby object_id. This is helpful
69
+ # when following an execution log with nested or interleaved interaction log lines.
70
+ def id_marker
71
+ "(id##{object_id})"
72
+ end
73
+
74
+ # @return [String] a prefix that indents each debug line according to the level of interactions nesting.
75
+ def indent
76
+ lvl = [0, calling_interactions.count].max
77
+ " " * lvl
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makwa
4
+ # @abstract Override {#execute_returning} and call {#returning} in the class body, passing in the symbol
5
+ # of the input you want returned. Guaranteed to return the returning input, with interaction errors
6
+ # merged into it.
7
+ class ReturningInteraction < ::Makwa::Interaction
8
+ class ReturnFilterInexistent < StandardError; end
9
+
10
+ class ReturningFilterNotSpecified < StandardError; end
11
+
12
+ class NotActiveModelErrorable < StandardError; end
13
+
14
+ define_callbacks(:execute_returning)
15
+
16
+ class << self
17
+ # @param (see ActiveInteraction::Runnable#initialize)
18
+ #
19
+ # @return (see ReturningInteraction#run_returning!)
20
+ def run_returning!(*args)
21
+ new(*args).send(:run_returning!)
22
+ end
23
+
24
+ # @param return_filter [Symbol] Name of the input filter to be returned
25
+ def returning(return_filter)
26
+ @return_filter = return_filter
27
+ end
28
+ end
29
+
30
+ # @abstract
31
+ #
32
+ # @raise [NotImplementedError]
33
+ def execute_returning
34
+ raise NotImplementedError, "You need to implemented the method #execute_returning in your interaction."
35
+ end
36
+
37
+ private
38
+
39
+ # @return [Object]
40
+ def run_returning!
41
+ @_interaction_result = return_input # {#result=} has side-effects
42
+ raise ReturningFilterNotSpecified unless self.class.instance_variable_defined?(:@return_filter)
43
+ raise ReturnFilterInexistent unless result
44
+ raise NotActiveModelErrorable unless result.respond_to?(:errors) && result.errors.respond_to?(:merge!)
45
+
46
+ # Run validations (explicitly, don't rely on #valid?)
47
+ validate
48
+ if errors_any?
49
+ # Add errors and values to the result object (so that the form can render them) and return the result object
50
+ return result
51
+ .tap { |r| r.errors.merge!(errors) }
52
+ .tap { |r| r.assign_attributes(inputs.except(@return_filter)) }
53
+ end
54
+
55
+ # Otherwise run the body of the interaction (along with any callbacks) ...
56
+ run_callbacks(:execute_returning) do
57
+ execute_returning
58
+ rescue ::Makwa::Interaction::Interrupt
59
+ # Do nothing
60
+ end
61
+
62
+ # ... and return the result, merging in any errors added in the body of the interaction that are not duplicates.
63
+ # Duplicates would occur if, for example, the body of the interaction calls
64
+ # `errors.merge!(<returning_filter>.errors)` as is often done in non-returning interactions.
65
+ result.tap do |r|
66
+ errors.each do |e|
67
+ r.errors.add(e.attribute, e.message) unless r.errors.added?(e.attribute, e.message)
68
+ end
69
+ end
70
+ end
71
+
72
+ # @return [Object]
73
+ def return_input
74
+ @return_input ||= inputs[self.class.instance_variable_get(:@return_filter)]
75
+ end
76
+
77
+ # @param other [Class] The other interaction.
78
+ #
79
+ # @return (see #result)
80
+ def compose(other, *args)
81
+ @_interaction_result = other.run_returning!(*args)
82
+
83
+ if block_given?
84
+ errors.merge!(@_interaction_result.errors)
85
+ yield @_interaction_result
86
+ end
87
+
88
+ @_interaction_result
89
+ rescue NotImplementedError
90
+ super(other, *args)
91
+ end
92
+ end
93
+ end
data/lib/makwa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Makwa
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/makwa.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "makwa/version"
3
+ require "active_interaction"
4
4
 
5
5
  module Makwa
6
- class Error < StandardError; end
7
- # Your code goes here...
8
6
  end
7
+
8
+ # Dependency boundary
9
+
10
+ require "makwa/interaction"
11
+ require "makwa/returning_interaction"
12
+ require "makwa/version"
data/makwa.gemspec CHANGED
@@ -3,14 +3,18 @@
3
3
  require_relative "lib/makwa/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "makwa"
7
- spec.version = Makwa::VERSION
8
- spec.authors = ["Jo Hund"]
9
- spec.email = ["jhund@clearcove.ca"]
10
-
11
- spec.summary = "Interactions for Ruby on Rails apps."
12
- spec.homepage = "https://github.com/animikii/makwa"
13
- spec.license = "MIT"
6
+ spec.name = "makwa"
7
+ spec.version = Makwa::VERSION
8
+ {
9
+ "Jo Hund" => "jo@animikii.com",
10
+ "Fabio Papa" => "fabio.papa@animikii.com"
11
+ }.tap do |hash|
12
+ spec.authors = hash.keys
13
+ spec.email = hash.values
14
+ end
15
+ spec.summary = "Interactions for Ruby on Rails apps."
16
+ spec.homepage = "https://github.com/animikii/makwa"
17
+ spec.license = "MIT"
14
18
  spec.required_ruby_version = ">= 2.4.0"
15
19
 
16
20
  spec.metadata["homepage_uri"] = spec.homepage
@@ -22,13 +26,10 @@ Gem::Specification.new do |spec|
22
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
28
  end
25
- spec.bindir = "exe"
26
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
29
  spec.require_paths = ["lib"]
28
30
 
29
- # Uncomment to register a new dependency of your gem
30
- # spec.add_dependency "example-gem", "~> 1.0"
31
+ spec.add_dependency "active_interaction", "~> 4.0"
31
32
 
32
- # For more information and examples about making a new gem, checkout our
33
- # guide at: https://bundler.io/guides/creating_gem.html
33
+ spec.add_development_dependency "standard"
34
+ spec.add_development_dependency "byebug"
34
35
  end
metadata CHANGED
@@ -1,18 +1,62 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makwa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jo Hund
8
+ - Fabio Papa
8
9
  autorequire:
9
- bindir: exe
10
+ bindir: bin
10
11
  cert_chain: []
11
- date: 2021-09-23 00:00:00.000000000 Z
12
- dependencies: []
12
+ date: 2021-10-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_interaction
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '4.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '4.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: standard
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: byebug
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
13
56
  description:
14
57
  email:
15
- - jhund@clearcove.ca
58
+ - jo@animikii.com
59
+ - fabio.papa@animikii.com
16
60
  executables: []
17
61
  extensions: []
18
62
  extra_rdoc_files: []
@@ -25,7 +69,10 @@ files:
25
69
  - Rakefile
26
70
  - bin/console
27
71
  - bin/setup
72
+ - doc/how_to_release_new_version.md
28
73
  - lib/makwa.rb
74
+ - lib/makwa/interaction.rb
75
+ - lib/makwa/returning_interaction.rb
29
76
  - lib/makwa/version.rb
30
77
  - makwa.gemspec
31
78
  homepage: https://github.com/animikii/makwa