haku 1.0.0 → 1.1.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: 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: