haku 1.0.0 → 1.1.0

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: b807f104854f0cd9619b5a3a5be55a5e9744e7eaef85ace5f775772395d9957b
4
- data.tar.gz: fb389738d56e37d6f397ee32316c7ad249ef95ad1d39f790c083742a0e6fad83
3
+ metadata.gz: d706591454ee0f992403b400e7dc75e621bccb120978050d98f55f2aaceca5bd
4
+ data.tar.gz: 18652ffbeff0a83d8a7344d7de7e7f4bb905d973a740fecc99a14a05d1258d46
5
5
  SHA512:
6
- metadata.gz: baa9206fa09e7aec2212a226fc66a0dd4a4fcb88ca437c95032c1e7f9fb244fda6e2fa9b7869d38c736a3c88970fa808bc12234f72d93d0d3ba741f3107a68e1
7
- data.tar.gz: 3fbcf48768c7125fb1e60c1b1b022cef94b34e6cfc1236ada836d559d2e4595776a12a441f6af2fe0fc7cd948675b43681479edeb66836bf436b3ea12e7e7294
6
+ metadata.gz: f4ad33422d9efcba85416ee72099e1c577b1172f6e4a40bea8c9d28cfd4edb8f3259eb5f04671a54ca67dcab0cc796bb407f39111d5ecb9fd30cc6d2d6bf235a
7
+ data.tar.gz: ee0e64b2f70d88f833cedbf96b56af02a9ffaaa17e29df5d582ae6b71a6199935e6897b8bbc704f4d2c035215be45b9767e5814275da002aa8836e627f5c5db8
data/.rubocop.yml CHANGED
@@ -12,6 +12,8 @@ AllCops:
12
12
  DisplayCopNames: true
13
13
  Exclude:
14
14
  - "**/bin/**/*"
15
+ - "**/gemfiles/**/*"
16
+ - "**/Appraisals"
15
17
  NewCops: enable
16
18
  TargetRubyVersion: 2.6
17
19
 
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.1.1
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "activesupport-6.0" do
2
+ gem "activesupport", "6.0"
3
+ end
4
+
5
+ appraise "activesupport-6.1" do
6
+ gem "activesupport", "6.1"
7
+ end
8
+
9
+ appraise "activesupport-7.0" do
10
+ gem "activesupport", "7.0"
11
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2022-04-05
3
+ ## [1.1.0] - 2022-04-19
4
+ - Allow to configure Haku using block
5
+ - Add Eventable module to fire events
6
+ - Add persist_resource to Resourceable
7
+ - Allow to declare inputs instead of create automatically
8
+ - Avoid using run to execute code. Using call is better
9
+ - Improve README
10
+ - Use Appraisal to test against multiple versions of some gems
4
11
 
12
+ ## [1.0.0] - 2022-04-11
5
13
  - Initial release
data/Gemfile CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- ruby "3.1.1"
6
-
7
5
  gemspec
8
6
 
7
+ gem "appraisal", github: "excid3/appraisal", branch: "fix-bundle-env"
9
8
  gem "minitest", "~> 5.0"
10
9
  gem "pry", "~> 0.14"
11
10
  gem "rake", "~> 13.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,17 @@
1
+ GIT
2
+ remote: https://github.com/excid3/appraisal.git
3
+ revision: 14855fc54ce88b42def871ce8bfd4259fbf06043
4
+ branch: fix-bundle-env
5
+ specs:
6
+ appraisal (2.4.1)
7
+ bundler
8
+ rake
9
+ thor (>= 0.14.0)
10
+
1
11
  PATH
2
12
  remote: .
3
13
  specs:
4
- haku (0.1.0)
14
+ haku (1.1.0)
5
15
  activesupport (>= 6.0, < 8.0)
6
16
 
7
17
  GEM
@@ -14,7 +24,7 @@ GEM
14
24
  tzinfo (~> 2.0)
15
25
  ast (2.4.2)
16
26
  coderay (1.1.3)
17
- concurrent-ruby (1.1.9)
27
+ concurrent-ruby (1.1.10)
18
28
  i18n (1.10.0)
19
29
  concurrent-ruby (~> 1.0)
20
30
  method_source (1.0.0)
@@ -45,6 +55,7 @@ GEM
45
55
  rubocop-rake (0.6.0)
46
56
  rubocop (~> 1.0)
47
57
  ruby-progressbar (1.11.0)
58
+ thor (1.2.1)
48
59
  tzinfo (2.0.4)
49
60
  concurrent-ruby (~> 1.0)
50
61
  unicode-display_width (2.1.0)
@@ -54,6 +65,7 @@ PLATFORMS
54
65
  x86_64-linux
55
66
 
56
67
  DEPENDENCIES
68
+ appraisal!
57
69
  haku!
58
70
  minitest (~> 5.0)
59
71
  pry (~> 0.14)
@@ -62,8 +74,5 @@ DEPENDENCIES
62
74
  rubocop-minitest (~> 0.19)
63
75
  rubocop-rake (~> 0.6)
64
76
 
65
- RUBY VERSION
66
- ruby 3.1.1p18
67
-
68
77
  BUNDLED WITH
69
78
  2.3.7
File without changes
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![CI](https://github.com/javierav/haku/workflows/CI/badge.svg)
4
4
 
5
- TODO: Write a better gem description.
5
+ A library for build simple service objects.
6
6
 
7
7
  ## Installation
8
8
 
@@ -14,11 +14,200 @@ gem 'haku'
14
14
 
15
15
  And then execute:
16
16
 
17
- $ bundle install
17
+ ```shell
18
+ bundle install
19
+ ```
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ ### Basic example
24
+
25
+ ````ruby
26
+ class Users::Update
27
+ include Haku::Core
28
+
29
+ input :user, :attributes
30
+ on_success :send_email
31
+
32
+ def call
33
+ if user.update(attributes)
34
+ success! resource: user
35
+ else
36
+ failure! resource: user, errors: user.errors
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def send_email
43
+ UserMailer.with(user: user).update.deliver_later
44
+ end
45
+ end
46
+
47
+ response = Users::Update.call(user: User.first, attributes: { name: "Javier" })
48
+
49
+ response.success? # => true
50
+ response.resource # => <User id="1" ...>
51
+ ````
52
+
53
+ ### Using resourceable helpers
54
+
55
+ ````ruby
56
+ class Users::Update
57
+ include Haku::Core
58
+ include Haku::Resourceable
59
+
60
+ input :user, :attributes
61
+ on_success :send_email
62
+
63
+ def call
64
+ update_resource(user, attributes)
65
+ end
66
+
67
+ private
68
+
69
+ def send_email
70
+ UserMailer.with(user: user).update.deliver_later
71
+ end
72
+ end
73
+ ````
74
+
75
+ ### Controller helpers
76
+
77
+ ```ruby
78
+ class UsersController < ApplicationController
79
+ before_action :find_user
80
+
81
+ def update
82
+ execute Users::Update, user: @user, attributes: update_params
83
+
84
+ if execution.success?
85
+ redirect_to user_path(execution.resource)
86
+ else
87
+ render :edit, errors: execution.errors
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def find_user
94
+ @user = User.find(params[:id])
95
+ end
96
+
97
+ def update_params
98
+ params.require(:user).permit(:first_name, :last_name)
99
+ end
100
+ end
101
+ ```
102
+
103
+ ### Using eventable
104
+
105
+ ````ruby
106
+ class Users::Update
107
+ include Haku::Core
108
+ include Haku::Resourceable
109
+ include Haku::Eventable
110
+
111
+ input :user, :attributes
112
+ event resource: :user
113
+
114
+ def call
115
+ update_resource(user, attributes)
116
+ end
117
+ end
118
+
119
+ Users::Update.call(user: User.first, attributes: { name: "Javier" })
120
+
121
+ # => call Event.create(name: "user:update", resource: User.first)
122
+ ````
123
+
124
+ ### Using parent class
125
+
126
+ ```ruby
127
+ class ApplicationAction
128
+ include Haku::Core
129
+ include Haku::Resourceable
130
+ include Haku::Eventable
131
+ end
132
+
133
+ class Users::Update < ApplicationAction
134
+ end
135
+ ```
136
+
137
+ ## Configure
138
+
139
+ ### Example
140
+
141
+ ```ruby
142
+ # config/initializers/haku.rb
143
+
144
+ Haku.configure do |config|
145
+ config.event_model = "EventLog"
146
+ end
147
+ ```
148
+
149
+ ### Allowed options
150
+
151
+ | Config | Description | Default value |
152
+ |:-----------------------------------|:-------------------------------------------------------|:---------------------------------------------------------|
153
+ | `enable_in_action_controller_base` | Include controller helpers in `ActionController::Base` | `true` |
154
+ | `enable_in_action_controller_api` | Include controller helpers in `ActionController::API` | `true` |
155
+ | `event_model` | Name of the model used for create events | `Event` |
156
+ | `event_properties` | List of attributes passed from service to event model | `%i[actor resource target context]` |
157
+ | `event_property_for_name` | Property used for name in event model | `:name` |
158
+ | `event_name` | String or Proc to determine the event name | Custom Proc. Example: `user:created` for `Users::Create` |
159
+
160
+
161
+ ## Resourceable
162
+
163
+ This module include helpers to works with *ActiveRecord* compatible model resources, invoking `success!` or `failure!`
164
+ based in the result of the performed operation.
165
+
166
+ ### create_resource
167
+
168
+ Call to `create` or `<singleton>_create` method of the `parent` object passing the `attributes` and storing
169
+ the result object in the `ivar` instance variable. Invoke `success!` if the model is persisted or `failure!` in other
170
+ case.
171
+
172
+ | parameter | type | description |
173
+ |--------------|----------|------------------------------------------------------------------|
174
+ | `parent` | `Object` | Parent object where new resource will be created |
175
+ | `attributes` | `Hash` | Attributes for create |
176
+ | `ivar` | `Symbol` | Name of the instance variable used to access to the new resource |
177
+ | `options` | `Hash` | Options hash |
178
+
179
+ #### options
180
+
181
+ | parameter | type | description |
182
+ |-------------|----------|----------------------------------------------------------------------|
183
+ | `singleton` | `Symbol` | If the resource should be created using `<singleton>_create` suffix. |
184
+
185
+ ### update_resource
186
+
187
+ Call to `update` method of the `resource` object passing `attributes`to it. Invoke `success!` if the model is updated or
188
+ `failure!` in other case.
189
+
190
+ | parameter | type | description |
191
+ |--------------|----------|------------------------|
192
+ | `resource` | `Object` | Resource to be updated |
193
+ | `attributes` | `Hash` | Attributes to update |
194
+
195
+ ### destroy_resource
196
+
197
+ Call to `destroy` method of the `resource`. Invoke `success!` if the model is destroyed or `failure!` in other case.
198
+
199
+ | parameter | type | description |
200
+ |--------------|----------|--------------------------|
201
+ | `resource` | `Object` | Resource to be destroyed |
202
+
203
+ ### persist_resource
204
+
205
+ | parameter | type | description |
206
+ |----------------|----------|---------------------------------------------|
207
+ | `resource` | `Object` | Resource to be destroyed |
208
+ | `save_options` | `Hash` | Options passed to `save` method of resource |
209
+
210
+ For more info please view the [source code](lib/haku/resourceable.rb) of the module.
22
211
 
23
212
  ## Development
24
213
 
@@ -26,15 +215,15 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
26
215
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
27
216
 
28
217
  To install this gem onto your local machine, run `bundle exec rake install`.
218
+
29
219
  To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
30
220
  which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to
31
221
  [rubygems.org](https://rubygems.org).
32
222
 
33
223
  ## Contributing
34
224
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/javierav/haku. This project is intended to be
36
- a safe, welcoming space for collaboration, and contributors are expected to adhere to the
37
- [code of conduct](https://github.com/javierav/haku/blob/development/CODE_OF_CONDUCT.md).
225
+ Bug reports and pull requests are welcome, please follow
226
+ [Github Flow](https://docs.github.com/en/get-started/quickstart/github-flow).
38
227
 
39
228
  ## Code of Conduct
40
229
 
@@ -43,4 +232,4 @@ follow the [code of conduct](https://github.com/javierav/haku/blob/development/C
43
232
 
44
233
  ## License
45
234
 
46
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
235
+ Copyright © 2022 Javier Aranda. Released under the terms of the [MIT license](LICENSE).
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.4"
6
+ gem "minitest", "~> 5.0"
7
+ gem "pry", "~> 0.14"
8
+ gem "rake", "~> 13.0"
9
+ gem "rubocop", "~> 1.21"
10
+ gem "rubocop-minitest", "~> 0.19"
11
+ gem "rubocop-rake", "~> 0.6"
12
+ gem "activesupport", "6.0"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.4"
6
+ gem "minitest", "~> 5.0"
7
+ gem "pry", "~> 0.14"
8
+ gem "rake", "~> 13.0"
9
+ gem "rubocop", "~> 1.21"
10
+ gem "rubocop-minitest", "~> 0.19"
11
+ gem "rubocop-rake", "~> 0.6"
12
+ gem "activesupport", "6.1"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.4"
6
+ gem "minitest", "~> 5.0"
7
+ gem "pry", "~> 0.14"
8
+ gem "rake", "~> 13.0"
9
+ gem "rubocop", "~> 1.21"
10
+ gem "rubocop-minitest", "~> 0.19"
11
+ gem "rubocop-rake", "~> 0.6"
12
+ gem "activesupport", "7.0"
13
+
14
+ gemspec path: "../"
data/lib/haku/core.rb CHANGED
@@ -9,15 +9,30 @@ module Haku
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
+ prepend Callable
13
+
12
14
  attr_reader :params
13
15
 
16
+ class_attribute :haku_inputs, default: []
14
17
  class_attribute :haku_success_callbacks, default: []
15
18
  class_attribute :haku_failure_callbacks, default: []
16
19
  end
17
20
 
18
21
  module ClassMethods
22
+ def inherited(base)
23
+ super
24
+
25
+ base.class_eval do
26
+ prepend Callable
27
+ end
28
+ end
29
+
19
30
  def call(params={})
20
- new(params).run
31
+ new(params).call
32
+ end
33
+
34
+ def input(*names)
35
+ self.haku_inputs += names
21
36
  end
22
37
 
23
38
  def on_success(*methods)
@@ -29,19 +44,24 @@ module Haku
29
44
  end
30
45
  end
31
46
 
32
- def initialize(params={})
33
- @params = params
47
+ module Callable
48
+ def call
49
+ result = super
34
50
 
35
- @params.each_key do |key|
36
- define_singleton_method(key) { @params[key] } unless respond_to?(key)
51
+ Result.new(_haku_status, _haku_response.merge(result: result)).tap do
52
+ _haku_run_callbacks
53
+ end
37
54
  end
38
55
  end
39
56
 
40
- def run
41
- result = call
57
+ def initialize(params={})
58
+ @params = params
59
+
60
+ @_haku_status = :success
61
+ @_haku_response = {}
42
62
 
43
- Result.new(_haku_status, _haku_response.merge(result: result)).tap do
44
- _haku_run_callbacks
63
+ self.class.haku_inputs.each do |name|
64
+ define_singleton_method(name) { @params[name] } unless respond_to?(name)
45
65
  end
46
66
  end
47
67
 
@@ -64,11 +84,11 @@ module Haku
64
84
  end
65
85
 
66
86
  def _haku_status
67
- @_haku_status || :success
87
+ @_haku_status
68
88
  end
69
89
 
70
90
  def _haku_response
71
- @_haku_response || {}
91
+ @_haku_response
72
92
  end
73
93
 
74
94
  def _haku_run_callbacks
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/class/attribute"
5
+
6
+ module Haku
7
+ module Eventable
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ class_attribute :haku_success_events, default: []
12
+ class_attribute :haku_failure_events, default: []
13
+
14
+ on_success :haku_process_events_for_success
15
+ on_failure :haku_process_events_for_failure
16
+ end
17
+
18
+ module ClassMethods
19
+ def event(options={})
20
+ on = options.delete(:on)&.to_sym || :success
21
+
22
+ send("haku_#{on}_events=", send("haku_#{on}_events") + [options])
23
+ end
24
+ end
25
+
26
+ def haku_process_events_for_success
27
+ haku_process_events(:success)
28
+ end
29
+
30
+ def haku_process_events_for_failure
31
+ haku_process_events(:failure)
32
+ end
33
+
34
+ def haku_process_events(on)
35
+ send("haku_#{on}_events").each do |evt|
36
+ haku_create_event(haku_prepare_event_data(evt))
37
+ end
38
+ end
39
+
40
+ def haku_prepare_event_data(evt, data={})
41
+ data.tap do
42
+ haku_event_data_base(data)
43
+ haku_event_data_name(data, evt)
44
+ haku_event_data_values(data, evt)
45
+ end
46
+ end
47
+
48
+ def haku_event_data_base(data)
49
+ Haku.event_properties.each do |property|
50
+ data[property] = send(property) if respond_to?(property)
51
+ end
52
+ end
53
+
54
+ def haku_process_value(value)
55
+ if value.respond_to?(:call)
56
+ instance_exec(&value)
57
+ else
58
+ value.is_a?(Symbol) ? send(value) : value
59
+ end
60
+ end
61
+
62
+ def haku_event_data_name(data, evt)
63
+ key = Haku.event_property_for_name.to_sym
64
+ data[key] = evt[key] || haku_process_value(Haku.event_name)
65
+ end
66
+
67
+ def haku_event_data_values(data, evt)
68
+ evt.except(Haku.event_property_for_name.to_sym).each_pair do |key, value|
69
+ data[key] = haku_process_value(value)
70
+ end
71
+ end
72
+
73
+ def haku_create_event(data)
74
+ Haku.event_model.safe_constantize&.create(data)
75
+ end
76
+ end
77
+ end
@@ -36,5 +36,18 @@ module Haku
36
36
  end
37
37
  end
38
38
  end
39
+
40
+ def persist_resource(resource, **save_options)
41
+ resource.tap do
42
+ if resource.save(save_options)
43
+ yield resource if block_given?
44
+ success! resource: resource
45
+ else
46
+ failure! resource: resource, errors: resource.errors
47
+ end
48
+ end
49
+ end
50
+
51
+ alias save_resource persist_resource
39
52
  end
40
53
  end
data/lib/haku/version.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Haku
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 0
6
+ MINOR = 1
7
7
  TINY = 0
8
8
  PRE = nil
9
9
 
data/lib/haku.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/attribute_accessors"
4
+ require "active_support/core_ext/string/inflections"
4
5
  require_relative "haku/core"
6
+ require_relative "haku/eventable"
5
7
  require_relative "haku/railtie" if defined?(Rails)
6
8
  require_relative "haku/resourceable"
7
9
  require_relative "haku/version"
@@ -9,4 +11,17 @@ require_relative "haku/version"
9
11
  module Haku
10
12
  mattr_accessor :enable_in_action_controller_base, default: true
11
13
  mattr_accessor :enable_in_action_controller_api, default: true
14
+ mattr_accessor :event_model, default: "Event"
15
+ mattr_accessor :event_properties, default: %i[actor resource target context]
16
+ mattr_accessor :event_property_for_name, default: :name
17
+ mattr_accessor :event_name, default: proc {
18
+ chain = self.class.name.underscore.split("/")
19
+ (chain[0...-1].map(&:singularize) + [chain.last]).join(":")
20
+ }
21
+
22
+ class << self
23
+ def configure
24
+ yield self
25
+ end
26
+ end
12
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haku
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Aranda
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-11 00:00:00.000000000 Z
11
+ date: 2022-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -36,23 +36,29 @@ email:
36
36
  executables: []
37
37
  extensions: []
38
38
  extra_rdoc_files:
39
- - LICENSE.txt
39
+ - LICENSE
40
40
  - README.md
41
41
  files:
42
42
  - ".editorconfig"
43
43
  - ".envrc"
44
44
  - ".pryrc"
45
45
  - ".rubocop.yml"
46
+ - ".tool-versions"
47
+ - Appraisals
46
48
  - CHANGELOG.md
47
49
  - CODE_OF_CONDUCT.md
48
50
  - Gemfile
49
51
  - Gemfile.lock
50
- - LICENSE.txt
52
+ - LICENSE
51
53
  - README.md
52
54
  - Rakefile
55
+ - gemfiles/activesupport_6.0.gemfile
56
+ - gemfiles/activesupport_6.1.gemfile
57
+ - gemfiles/activesupport_7.0.gemfile
53
58
  - lib/haku.rb
54
59
  - lib/haku/controller.rb
55
60
  - lib/haku/core.rb
61
+ - lib/haku/eventable.rb
56
62
  - lib/haku/railtie.rb
57
63
  - lib/haku/resourceable.rb
58
64
  - lib/haku/result.rb
@@ -62,8 +68,8 @@ licenses:
62
68
  - MIT
63
69
  metadata:
64
70
  homepage_uri: https://github.com/javierav/haku
65
- source_code_uri: https://github.com/javierav/haku/tree/v1.0.0
66
- changelog_uri: https://github.com/javierav/haku/blob/v1.0.0/CHANGELOG.md
71
+ source_code_uri: https://github.com/javierav/haku/tree/v1.1.0
72
+ changelog_uri: https://github.com/javierav/haku/blob/v1.1.0/CHANGELOG.md
67
73
  rubygems_mfa_required: 'true'
68
74
  post_install_message:
69
75
  rdoc_options: