activeduty 0.1.0 → 0.1.1

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: 3851ef284433a3cf609e6934fee1eb357c0f1a8d97bd2db3677ef16732adc2a1
4
- data.tar.gz: 3a24b9d50c907e610b17062ff1468fc3bde330150da2492132c255986c99a64b
3
+ metadata.gz: 2b879bfa0f660945b57f5b87a67ddef1bf55dd91fdece4c5dc07820d93950d90
4
+ data.tar.gz: 13c31dbba265e4d3e738a417595633deee7e837e23eaff04b5154b3f299ca77a
5
5
  SHA512:
6
- metadata.gz: 62d7527dced5eca2869d9ad7ce69b7ecfdd1b4ecf0c3a2249f72e18790fbfca384f3ab49798ca36cdc9021650a2c7864df2be2beed4d64d63f5b18884146a8c3
7
- data.tar.gz: 126a2cc3b05c4dbd1cc7b9688c5b96f0d863948c8de9a97378acbd429b5030d9cda087873ffe25edc057b013cdbc7c54195cdff81a0bdc638ff2de43aaa7cf22
6
+ metadata.gz: 8833e8338c11c2cc0c398485268e0d3947079c3b109efc071ee025018e03959b051a6c2b9d4d44b00550071536816aaa9be6d68b7376773654425a7fdc4773e1
7
+ data.tar.gz: 44b5d6e28ab6ba25f9fd150a9b9df4f3f3ca670a33bd39d426e01b107688ab3aaa94dca3c20165503f995d9ea2571cb0ef969cb5da19e4845ef6adbcd91a2f5d
@@ -0,0 +1,17 @@
1
+ # 0.1.1
2
+
3
+ ## Breaking
4
+
5
+ None.
6
+
7
+ ## Fixes
8
+
9
+ None.
10
+
11
+ ## Features
12
+
13
+ * Allow `init_with` to accept default arguments.
14
+
15
+ # 0.1
16
+
17
+ Release.
data/README.md CHANGED
@@ -1,3 +1,157 @@
1
1
  # ActiveDuty
2
2
 
3
- Service objects.
3
+ Service objects, based loosely on [Interactor](https://github.com/collectiveidea/interactor).
4
+
5
+ ## Design
6
+
7
+ Define the logic in `run` and call it with `call`:
8
+
9
+ ## Basic usage
10
+
11
+ ```ruby
12
+ class AuthenticateUser < ActiveDuty::Base
13
+ def initialize(email, password)
14
+ @email, @password = email, password
15
+ end
16
+
17
+ def run
18
+ if user = User.authenticate(@email, @password)
19
+ context.user = user
20
+ else
21
+ fail!
22
+ end
23
+ end
24
+ end
25
+ ```
26
+
27
+ Usage:
28
+
29
+ ```
30
+ service = AuthenticateUser.new("josh@example.com", password: "password")
31
+ service.call
32
+ if service.success?
33
+ # do something
34
+ else
35
+ puts service.errors.inspect
36
+ end
37
+ ```
38
+
39
+ ## Advanced usage
40
+
41
+ ### init_with
42
+
43
+ A DSL for initializing.
44
+
45
+ #### Ordered arguments
46
+
47
+ ```
48
+ class AuthenticateUser < ActiveDuty::Base
49
+ init_with :username, :password
50
+ end
51
+ ```
52
+
53
+ Is the equivalent of:
54
+
55
+ ```
56
+ class AuthenticateUser < ActiveDuty::Base
57
+ attr_reader :username, :password
58
+ def initialize(username, password)
59
+ @username, @password = username, password
60
+ end
61
+ end
62
+ ```
63
+
64
+ #### Keyword arguments
65
+
66
+ ```
67
+ class AuthenticateUser < ActiveDuty::Base
68
+ init_with uname: :username, pw: :password
69
+ end
70
+ ```
71
+
72
+ Is the equivalent of:
73
+
74
+ ```
75
+ class AuthenticateUser < ActiveDuty::Base
76
+ attr_reader :username, :password
77
+ def initialize(uname:, pw:)
78
+ @username, @password = uname, pw
79
+ end
80
+ end
81
+ ```
82
+
83
+ #### Defaults
84
+
85
+ ```
86
+ class AuthenticateUser < ActiveDuty::Base
87
+ init_with :username, [:password, nil]
88
+ end
89
+ ```
90
+
91
+ Is the equivalent of:
92
+
93
+ ```
94
+ class AuthenticateUser < ActiveDuty::Base
95
+ attr_reader :username, :password
96
+ def initialize(username, password = nil)
97
+ @username, @password = username, password
98
+ end
99
+ end
100
+ ```
101
+
102
+ #### Keyword arguments
103
+
104
+ ```
105
+ class AuthenticateUser < ActiveDuty::Base
106
+ init_with uname: [nil, :username], pw: ["good-password", :password]
107
+ end
108
+ ```
109
+
110
+ Is the equivalent of:
111
+
112
+ ```
113
+ class AuthenticateUser < ActiveDuty::Base
114
+ attr_reader :username, :password
115
+ def initialize(uname: nil, pw: "good-password")
116
+ @username, @password = uname, pw
117
+ end
118
+ end
119
+ ```
120
+
121
+ ### Callbacks
122
+
123
+ Supports `after_initialize`, `before_call`, `after_call`. They use `ActiveModel::Callbacks` under the hood, so the API is familiar.
124
+
125
+ ### Context
126
+
127
+ An `OpenStruct` for a setting information during the runtime of your service object. Exposed via `context`.
128
+
129
+ ### Errors
130
+
131
+ Uses `ActiveModel::Errors` under the hood.
132
+
133
+ ### Rollbacks
134
+
135
+ If your call fails and you need to do some housekeeping, define a rollback:
136
+
137
+ ```ruby
138
+ class AuthenticateUser < ActiveDuty::Base
139
+ def rollback
140
+ # do something
141
+ end
142
+ end
143
+ ```
144
+
145
+ Or class-level:
146
+
147
+ ```ruby
148
+ class AuthenticateUser < ActiveDuty::Base
149
+ rollback do
150
+ # do something
151
+ end
152
+ end
153
+ ```
154
+
155
+ ### Failing
156
+
157
+ Need to fail? Call `fail!`
@@ -6,20 +6,27 @@ module ActiveDuty
6
6
  define_model_callbacks :call, only: [:before, :after, :around]
7
7
 
8
8
  def self.after_initialize(&block)
9
- @_after_initialize_block = block
9
+ @_after_initialize_callbacks ||= []
10
+ @_after_initialize_callbacks << block
10
11
  end
11
12
 
12
- def self._after_initialize_block
13
- if defined?(@_after_initialize_block)
14
- @_after_initialize_block
13
+ def self._after_initialize_callbacks
14
+ if defined?(@_after_initialize_callbacks)
15
+ @_after_initialize_callbacks
15
16
  else
16
17
  nil
17
18
  end
18
19
  end
19
20
 
20
21
  def after_initialize!
21
- if self.class._after_initialize_block
22
- instance_exec(self, &self.class._after_initialize_block)
22
+ if self.class._after_initialize_callbacks
23
+ self.class._after_initialize_callbacks.each do |callback|
24
+ if callback.is_a?(Symbol)
25
+ send(callback)
26
+ else
27
+ instance_exec(self, &callback)
28
+ end
29
+ end
23
30
  end
24
31
  end
25
32
  end
@@ -4,28 +4,100 @@ module ActiveDuty
4
4
  module ClassMethods
5
5
  def init_with(*args)
6
6
  kwargs = args.extract_options!
7
-
8
7
  if kwargs.empty?
9
- define_method :initialize do |*initialize_args|
10
- args.zip(initialize_args) do |name, value|
11
- instance_variable_set("@#{name}", value)
8
+ init_from_ordered(args)
9
+ else
10
+ init_from_kw(kwargs)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ # initialize from ordered arguments
17
+ #
18
+ # init_with :username, :password
19
+ # def initialize(username, password)
20
+ # @username = username
21
+ # @password = password
22
+ #
23
+ # init_with [:username], [:password, nil], [:email, "no email"], [:options, {}]
24
+ # def initialize(username, password = nil, email: "no email", options = {})
25
+ # @username = username
26
+ # @password = password
27
+ # @email = email
28
+ # @options = options
29
+ def init_from_ordered(args)
30
+ init_string = []
31
+ args.each do |arg|
32
+ str = ""
33
+ if arg.is_a?(Array)
34
+ if arg.size == 2
35
+ if arg[1].is_a?(String)
36
+ str << "#{arg[0]} = \"#{arg[1]}\""
37
+ else
38
+ str << "#{arg[0]} = #{arg[1]}"
39
+ end
40
+ else
41
+ str << "#{arg[0]}"
12
42
  end
13
- self.class.attr_reader *args
43
+ else
44
+ str << "#{arg}"
14
45
  end
15
- elsif kwargs.is_a?(Hash)
16
- class_eval <<-METHOD, __FILE__, __LINE__ + 1
17
- def initialize(#{kwargs.keys.map { |key| "#{key}:" }.join(', ')})
18
- #{kwargs.map { |key, value|
19
- "
20
- instance_variable_set(:\"@#{value}\", #{key})
21
- self.class.attr_reader :#{value}
22
- "
23
- }.join("\n")
24
- }
25
- end
26
- METHOD
46
+ init_string << str
27
47
  end
48
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
49
+ def initialize(#{init_string.join(', ')})
50
+ #{args.map { |arg|
51
+ if arg.is_a?(Array)
52
+ "instance_variable_set(:\"@#{arg[0]}\", #{arg[0]})
53
+ self.class.attr_reader :#{arg[0]}"
54
+ else
55
+ "instance_variable_set(:\"@#{arg}\", #{arg})
56
+ self.class.attr_reader :#{arg}"
57
+ end
58
+ }.join("\n")
59
+ }
60
+ end
61
+ METHOD
62
+ end
63
+
64
+ # Initialize with keyword args.
65
+ #
66
+ # { username: :user } will
67
+ # def initialize(username:)
68
+ # @user = username
69
+ #
70
+ # { username: ["Bob", :user] } will
71
+ # def initialize(username: "Bob")
72
+ # @user = username
73
+ def init_from_kw(args)
28
74
 
75
+ initializer_string = []
76
+ args.each do |key, values|
77
+ str = "#{key}:"
78
+ if values.is_a?(Array) && values.size == 2
79
+ if values[0].is_a?(String)
80
+ str += " \"#{values[0]}\""
81
+ else
82
+ str += "#{values[0]}"
83
+ end
84
+ end
85
+ initializer_string << str
86
+ end
87
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
88
+ def initialize(#{initializer_string.join(', ')})
89
+ #{args.map { |key, values|
90
+ if values.is_a?(Array)
91
+ "instance_variable_set(:\"@#{values[1]}\", #{key})
92
+ self.class.attr_reader :#{values[1]}"
93
+ else
94
+ "instance_variable_set(:\"@#{values}\", #{key})
95
+ self.class.attr_reader :#{values}"
96
+ end
97
+ }.join("\n")
98
+ }
99
+ end
100
+ METHOD
29
101
  end
30
102
 
31
103
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveDuty
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeduty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Brody
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-15 00:00:00.000000000 Z
11
+ date: 2020-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -86,6 +86,7 @@ executables: []
86
86
  extensions: []
87
87
  extra_rdoc_files: []
88
88
  files:
89
+ - CHANGELOG.md
89
90
  - README.md
90
91
  - lib/active_duty.rb
91
92
  - lib/active_duty/base.rb