activeduty 0.1.0 → 0.1.1

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