active_interaction 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +27 -3
- data/README.md +8 -6
- data/lib/active_interaction.rb +5 -3
- data/lib/active_interaction/active_model.rb +29 -0
- data/lib/active_interaction/base.rb +82 -116
- data/lib/active_interaction/errors.rb +79 -5
- data/lib/active_interaction/filter.rb +195 -21
- data/lib/active_interaction/filters.rb +26 -0
- data/lib/active_interaction/filters/array_filter.rb +22 -25
- data/lib/active_interaction/filters/boolean_filter.rb +12 -12
- data/lib/active_interaction/filters/date_filter.rb +32 -5
- data/lib/active_interaction/filters/date_time_filter.rb +34 -7
- data/lib/active_interaction/filters/file_filter.rb +12 -9
- data/lib/active_interaction/filters/float_filter.rb +13 -11
- data/lib/active_interaction/filters/hash_filter.rb +36 -17
- data/lib/active_interaction/filters/integer_filter.rb +13 -11
- data/lib/active_interaction/filters/model_filter.rb +15 -15
- data/lib/active_interaction/filters/string_filter.rb +19 -8
- data/lib/active_interaction/filters/symbol_filter.rb +29 -0
- data/lib/active_interaction/filters/time_filter.rb +38 -16
- data/lib/active_interaction/method_missing.rb +18 -0
- data/lib/active_interaction/overload_hash.rb +1 -0
- data/lib/active_interaction/validation.rb +19 -0
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/active_model_spec.rb +33 -0
- data/spec/active_interaction/base_spec.rb +54 -48
- data/spec/active_interaction/errors_spec.rb +99 -0
- data/spec/active_interaction/filter_spec.rb +12 -20
- data/spec/active_interaction/filters/array_filter_spec.rb +50 -28
- data/spec/active_interaction/filters/boolean_filter_spec.rb +15 -15
- data/spec/active_interaction/filters/date_filter_spec.rb +30 -18
- data/spec/active_interaction/filters/date_time_filter_spec.rb +31 -19
- data/spec/active_interaction/filters/file_filter_spec.rb +7 -7
- data/spec/active_interaction/filters/float_filter_spec.rb +13 -11
- data/spec/active_interaction/filters/hash_filter_spec.rb +38 -29
- data/spec/active_interaction/filters/integer_filter_spec.rb +18 -8
- data/spec/active_interaction/filters/model_filter_spec.rb +24 -20
- data/spec/active_interaction/filters/string_filter_spec.rb +14 -8
- data/spec/active_interaction/filters/symbol_filter_spec.rb +24 -0
- data/spec/active_interaction/filters/time_filter_spec.rb +33 -69
- data/spec/active_interaction/filters_spec.rb +21 -0
- data/spec/active_interaction/i18n_spec.rb +0 -15
- data/spec/active_interaction/integration/array_interaction_spec.rb +2 -22
- data/spec/active_interaction/integration/hash_interaction_spec.rb +5 -25
- data/spec/active_interaction/integration/symbol_interaction_spec.rb +5 -0
- data/spec/active_interaction/method_missing_spec.rb +69 -0
- data/spec/active_interaction/validation_spec.rb +55 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/filters.rb +168 -14
- data/spec/support/interactions.rb +11 -13
- metadata +31 -13
- data/lib/active_interaction/filter_method.rb +0 -13
- data/lib/active_interaction/filter_methods.rb +0 -26
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +0 -25
- data/spec/active_interaction/filter_method_spec.rb +0 -43
- data/spec/active_interaction/filter_methods_spec.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddc5d64fad3052b09b16259d6aae6760411b384b
|
4
|
+
data.tar.gz: 1c3569cfc819b0153c2c875cf5674c29382fc956
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 399f01cd79b55412083c29364afa80e53660e28ccbfc9d01788a138e30152ee61f4e6307e7a8f496a1b058557555ece132bf496b9e7d623b580e9414e203b030
|
7
|
+
data.tar.gz: c25734f3428395f3c063c7a6b1f867b65107dc806a7e5a391b38d8692fcd46a391cc8f3259aca4df2911bfb377fe45adb96393f7738eb2cfc7acde95cf401d86
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,33 @@
|
|
1
1
|
# [Master][]
|
2
2
|
|
3
|
-
# [0.
|
3
|
+
# [0.6.1][] (2013-11-14)
|
4
|
+
|
5
|
+
- Re-release. Forgot to merge into master.
|
6
|
+
|
7
|
+
# [0.6.0][] (2013-11-14)
|
8
|
+
|
9
|
+
- Error class now end with `Error`.
|
10
|
+
- By default, strip unlisted keys from hashes. To retain the old behavior, set
|
11
|
+
`strip: false` on a hash filter.
|
12
|
+
- Prevent specifying defaults (other than `nil` or `{}`) on hash filters. Set
|
13
|
+
defaults on the nested filters instead.
|
14
|
+
- Add ability to introspect interactions with `filters`.
|
15
|
+
- Fix bug that prevented listing multiple attributes in a hash filter.
|
16
|
+
- Allow getting all of the user-supplied inputs in an interaction with
|
17
|
+
`inputs`.
|
18
|
+
- Fix bug that prevented hash filters from being nested in array filters.
|
19
|
+
- Replace `allow_nil: true` with `default: nil`.
|
20
|
+
- Refactor internals.
|
21
|
+
- Add a symbol filter.
|
22
|
+
- Allow adding symbolic errors with `errors.add_sym` and retrieving them with
|
23
|
+
`errors.symbolic`.
|
24
|
+
|
25
|
+
# [0.5.0][] (2013-10-16)
|
4
26
|
|
5
27
|
- Allow adding errors in `execute` method with `errors.add`.
|
6
28
|
- Prevent manually setting the outcome's result.
|
7
29
|
|
8
|
-
# [0.4.0][]
|
30
|
+
# [0.4.0][] (2013-08-15)
|
9
31
|
|
10
32
|
- Support i18n translations.
|
11
33
|
|
@@ -48,7 +70,9 @@
|
|
48
70
|
|
49
71
|
- Initial release.
|
50
72
|
|
51
|
-
[master]: https://github.com/orgsync/active_interaction/compare/v0.
|
73
|
+
[master]: https://github.com/orgsync/active_interaction/compare/v0.6.1...master
|
74
|
+
[0.6.1]: https://github.com/orgsync/active_interaction/compare/v0.6.0...v0.6.1
|
75
|
+
[0.6.0]: https://github.com/orgsync/active_interaction/compare/v0.5.0...v0.6.0
|
52
76
|
[0.5.0]: https://github.com/orgsync/active_interaction/compare/v0.4.0...v0.5.0
|
53
77
|
[0.4.0]: https://github.com/orgsync/active_interaction/compare/v0.3.0...v0.4.0
|
54
78
|
[0.3.0]: https://github.com/orgsync/active_interaction/compare/v0.2.2...v0.3.0
|
data/README.md
CHANGED
@@ -15,7 +15,8 @@ to this.
|
|
15
15
|
Take back control. Slim down models and wrangle monstrous controller
|
16
16
|
methods with ActiveInteraction.
|
17
17
|
|
18
|
-
|
18
|
+
Read more on the [project page][] or check out the full [documentation][]
|
19
|
+
on RubyDoc.info.
|
19
20
|
|
20
21
|
## Installation
|
21
22
|
|
@@ -24,7 +25,7 @@ This project uses [semantic versioning][].
|
|
24
25
|
Add it to your Gemfile:
|
25
26
|
|
26
27
|
```ruby
|
27
|
-
gem 'active_interaction', '~> 0.
|
28
|
+
gem 'active_interaction', '~> 0.6.1'
|
28
29
|
```
|
29
30
|
|
30
31
|
And then execute:
|
@@ -46,7 +47,7 @@ models ensure that certain options are provided and that those
|
|
46
47
|
options are in the format you want them in. If the options are valid
|
47
48
|
it will call `execute`, store the return value of that method in
|
48
49
|
`result`, and return an instance of your ActiveInteraction::Base
|
49
|
-
subclass. Let's
|
50
|
+
subclass. Let's look at a simple example:
|
50
51
|
|
51
52
|
```ruby
|
52
53
|
# Define an interaction that signs up a user.
|
@@ -55,7 +56,7 @@ class UserSignup < ActiveInteraction::Base
|
|
55
56
|
string :email, :name
|
56
57
|
|
57
58
|
# optional
|
58
|
-
boolean :newsletter_subscribe,
|
59
|
+
boolean :newsletter_subscribe, default: nil
|
59
60
|
|
60
61
|
# ActiveRecord validations
|
61
62
|
validates :email, format: EMAIL_REGEX
|
@@ -160,10 +161,10 @@ end
|
|
160
161
|
integer :age
|
161
162
|
boolean :is_special
|
162
163
|
model :account
|
163
|
-
array :tags,
|
164
|
+
array :tags, default: nil do
|
164
165
|
string
|
165
166
|
end
|
166
|
-
hash :prefs,
|
167
|
+
hash :prefs, default: nil do
|
167
168
|
boolean :smoking
|
168
169
|
boolean :view
|
169
170
|
end
|
@@ -258,4 +259,5 @@ This project was inspired by the fantastic work done in [Mutations][].
|
|
258
259
|
[documentation]: http://rubydoc.info/github/orgsync/active_interaction
|
259
260
|
[gem version]: https://badge.fury.io/rb/active_interaction.png
|
260
261
|
[mutations]: https://github.com/cypriss/mutations
|
262
|
+
[project page]: http://orgsync.github.io/active_interaction/
|
261
263
|
[semantic versioning]: http://semver.org
|
data/lib/active_interaction.rb
CHANGED
@@ -2,11 +2,10 @@ require 'active_model'
|
|
2
2
|
|
3
3
|
require 'active_interaction/version'
|
4
4
|
require 'active_interaction/errors'
|
5
|
+
require 'active_interaction/active_model'
|
6
|
+
require 'active_interaction/method_missing'
|
5
7
|
require 'active_interaction/overload_hash'
|
6
8
|
require 'active_interaction/filter'
|
7
|
-
require 'active_interaction/filter_method'
|
8
|
-
require 'active_interaction/filter_methods'
|
9
|
-
require 'active_interaction/filters/abstract_date_time_filter'
|
10
9
|
require 'active_interaction/filters/array_filter'
|
11
10
|
require 'active_interaction/filters/boolean_filter'
|
12
11
|
require 'active_interaction/filters/date_filter'
|
@@ -17,7 +16,10 @@ require 'active_interaction/filters/hash_filter'
|
|
17
16
|
require 'active_interaction/filters/integer_filter'
|
18
17
|
require 'active_interaction/filters/model_filter'
|
19
18
|
require 'active_interaction/filters/string_filter'
|
19
|
+
require 'active_interaction/filters/symbol_filter'
|
20
20
|
require 'active_interaction/filters/time_filter'
|
21
|
+
require 'active_interaction/filters'
|
22
|
+
require 'active_interaction/validation'
|
21
23
|
require 'active_interaction/base'
|
22
24
|
|
23
25
|
I18n.backend.load_translations(
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveInteraction
|
2
|
+
# @private
|
3
|
+
module ActiveModel
|
4
|
+
extend ::ActiveSupport::Concern
|
5
|
+
|
6
|
+
extend ::ActiveModel::Naming
|
7
|
+
include ::ActiveModel::Conversion
|
8
|
+
include ::ActiveModel::Validations
|
9
|
+
|
10
|
+
def new_record?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def persisted?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def i18n_scope
|
19
|
+
self.class.i18n_scope
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
module ClassMethods
|
24
|
+
def i18n_scope
|
25
|
+
:active_interaction
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -15,7 +15,7 @@ module ActiveInteraction
|
|
15
15
|
# integer :a, :b
|
16
16
|
#
|
17
17
|
# # Optional
|
18
|
-
# integer :c,
|
18
|
+
# integer :c, default: nil
|
19
19
|
#
|
20
20
|
# def execute
|
21
21
|
# sum = a + b
|
@@ -30,53 +30,59 @@ module ActiveInteraction
|
|
30
30
|
# p outcome.errors
|
31
31
|
# end
|
32
32
|
class Base
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
include ActiveModel
|
34
|
+
extend MethodMissing
|
35
|
+
extend OverloadHash
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
validate do
|
38
|
+
Validation.validate(self.class.filters, inputs).each do |error|
|
39
|
+
errors.add_sym(*error)
|
40
|
+
end
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
false
|
45
|
-
end
|
43
|
+
validate do
|
44
|
+
return unless instance_variable_defined?(:@_interaction_runtime_errors)
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
46
|
+
@_interaction_runtime_errors.symbolic.each do |attribute, symbols|
|
47
|
+
symbols.each { |symbol| errors.add_sym(attribute, symbol) }
|
48
|
+
end
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
@_interaction_runtime_errors.messages.each do |attribute, messages|
|
51
|
+
messages.each { |message| errors.add(attribute, message) }
|
52
|
+
end
|
55
53
|
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
# Returns the inputs provided to {.run} or {.run!} after being cast based
|
56
|
+
# on the filters in the class.
|
57
|
+
#
|
58
|
+
# @return [Hash{Symbol => Object}] All inputs passed to {.run} or {.run!}.
|
59
|
+
#
|
60
|
+
# @since 0.6.0
|
61
|
+
def inputs
|
62
|
+
self.class.filters.reduce({}) do |h, filter|
|
63
|
+
h[filter.name] = send(filter.name)
|
64
|
+
h
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
68
|
+
# @param options [Hash{Symbol => Object}] Attribute values to set.
|
69
|
+
#
|
66
70
|
# @private
|
67
71
|
def initialize(options = {})
|
68
|
-
options = options.
|
72
|
+
options = options.symbolize_keys
|
73
|
+
|
74
|
+
options.each do |key, value|
|
75
|
+
if key.to_s.start_with?('_interaction_')
|
76
|
+
raise InvalidValueError, key.inspect
|
77
|
+
end
|
69
78
|
|
70
|
-
|
71
|
-
raise ArgumentError, ':result is reserved and can not be used'
|
79
|
+
instance_variable_set("@#{key}", value)
|
72
80
|
end
|
73
81
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
else
|
79
|
-
instance_variable_set("@#{attribute}", value)
|
82
|
+
self.class.filters.each do |filter|
|
83
|
+
begin
|
84
|
+
send("#{filter.name}=", filter.clean(options[filter.name]))
|
85
|
+
rescue InvalidValueError, MissingValueError
|
80
86
|
end
|
81
87
|
end
|
82
88
|
end
|
@@ -87,6 +93,8 @@ module ActiveInteraction
|
|
87
93
|
# This method is run in a transaction if ActiveRecord is available.
|
88
94
|
#
|
89
95
|
# @raise [NotImplementedError] if the method is not defined.
|
96
|
+
#
|
97
|
+
# @abstract
|
90
98
|
def execute
|
91
99
|
raise NotImplementedError
|
92
100
|
end
|
@@ -97,12 +105,22 @@ module ActiveInteraction
|
|
97
105
|
# @return [Nil] if there are validation errors.
|
98
106
|
# @return [Object] if there are no validation errors.
|
99
107
|
def result
|
100
|
-
@_interaction_result
|
108
|
+
symbol = :'@_interaction_result'
|
109
|
+
if instance_variable_defined?(symbol)
|
110
|
+
instance_variable_get(symbol)
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# @private
|
117
|
+
def errors
|
118
|
+
@_interaction_errors ||= Errors.new(self)
|
101
119
|
end
|
102
120
|
|
103
121
|
# @private
|
104
122
|
def valid?(*args)
|
105
|
-
super ||
|
123
|
+
super || @_interaction_result = nil
|
106
124
|
end
|
107
125
|
|
108
126
|
# @private
|
@@ -115,27 +133,32 @@ module ActiveInteraction
|
|
115
133
|
yield
|
116
134
|
end
|
117
135
|
end
|
118
|
-
private_class_method :transaction
|
119
136
|
|
120
|
-
#
|
121
|
-
#
|
137
|
+
# Get all the filters defined on this interaction.
|
138
|
+
#
|
139
|
+
# @return [Filters]
|
140
|
+
#
|
141
|
+
# @since 0.6.0
|
142
|
+
def self.filters
|
143
|
+
@_interaction_filters ||= Filters.new
|
144
|
+
end
|
122
145
|
|
123
146
|
# Runs validations and if there are no errors it will call {#execute}.
|
124
147
|
#
|
125
|
-
# @
|
148
|
+
# @param (see #initialize)
|
126
149
|
#
|
127
150
|
# @return [ActiveInteraction::Base] An instance of the class `run` is
|
128
151
|
# called on.
|
129
|
-
def self.run(
|
130
|
-
new(
|
152
|
+
def self.run(*args)
|
153
|
+
new(*args).tap do |interaction|
|
131
154
|
if interaction.valid?
|
132
155
|
result = transaction { interaction.execute }
|
133
156
|
|
134
157
|
if interaction.errors.empty?
|
135
158
|
interaction.instance_variable_set(:@_interaction_result, result)
|
136
159
|
else
|
137
|
-
interaction.instance_variable_set(
|
138
|
-
interaction.errors.dup)
|
160
|
+
interaction.instance_variable_set(
|
161
|
+
:@_interaction_runtime_errors, interaction.errors.dup)
|
139
162
|
end
|
140
163
|
end
|
141
164
|
end
|
@@ -144,93 +167,36 @@ module ActiveInteraction
|
|
144
167
|
# Like {.run} except that it returns the value of {#execute} or raises an
|
145
168
|
# exception if there were any validation errors.
|
146
169
|
#
|
147
|
-
# @
|
148
|
-
#
|
149
|
-
# @raise [InteractionInvalid] if there are any errors on the model.
|
170
|
+
# @param (see .run)
|
150
171
|
#
|
151
172
|
# @return The return value of {#execute}.
|
152
|
-
|
153
|
-
|
173
|
+
#
|
174
|
+
# @raise [InteractionInvalidError] if there are any errors on the model.
|
175
|
+
def self.run!(*args)
|
176
|
+
outcome = run(*args)
|
154
177
|
if outcome.invalid?
|
155
|
-
raise
|
178
|
+
raise InteractionInvalidError, outcome.errors.full_messages.join(', ')
|
156
179
|
end
|
157
180
|
outcome.result
|
158
181
|
end
|
159
182
|
|
160
183
|
# @private
|
161
|
-
def self.method_missing(
|
162
|
-
|
163
|
-
|
164
|
-
args.each do |attribute|
|
165
|
-
set_up_reader(attribute, filter, options, &block)
|
166
|
-
set_up_writer(attribute, filter, options, &block)
|
167
|
-
set_up_validator(attribute, type, filter, options, &block)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
private_class_method :method_missing
|
171
|
-
|
172
|
-
# @private
|
173
|
-
def self.set_up_reader(attribute, filter, options, &block)
|
174
|
-
default = nil
|
175
|
-
if options.has_key?(:default)
|
176
|
-
begin
|
177
|
-
default = filter.
|
178
|
-
prepare(attribute, options[:default], options, &block)
|
179
|
-
rescue InvalidNestedValue, InvalidValue
|
180
|
-
raise InvalidDefaultValue
|
181
|
-
end
|
182
|
-
end
|
184
|
+
def self.method_missing(*args, &block)
|
185
|
+
super do |klass, names, options|
|
186
|
+
raise InvalidFilterError, 'no name' if names.empty?
|
183
187
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
instance_variable_get(symbol)
|
188
|
-
else
|
189
|
-
default
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
private_class_method :set_up_reader
|
194
|
-
|
195
|
-
# @private
|
196
|
-
def self.set_up_writer(attribute, filter, options, &block)
|
197
|
-
attr_writer attribute
|
198
|
-
|
199
|
-
writer = "_filter__#{attribute}="
|
200
|
-
|
201
|
-
define_method(writer) do |value|
|
202
|
-
value =
|
203
|
-
begin
|
204
|
-
filter.prepare(attribute, value, options, &block)
|
205
|
-
rescue InvalidNestedValue, InvalidValue, MissingValue
|
206
|
-
value
|
188
|
+
names.each do |attribute|
|
189
|
+
if attribute.to_s.start_with?('_interaction_')
|
190
|
+
raise InvalidFilterError, attribute.inspect
|
207
191
|
end
|
208
|
-
instance_variable_set("@#{attribute}", value)
|
209
|
-
end
|
210
|
-
private writer
|
211
|
-
end
|
212
|
-
private_class_method :set_up_writer
|
213
192
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
validate validator
|
193
|
+
filter = klass.new(attribute, options, &block)
|
194
|
+
filters.add(filter)
|
195
|
+
attr_accessor filter.name
|
219
196
|
|
220
|
-
|
221
|
-
begin
|
222
|
-
filter.prepare(attribute, send(attribute), options, &block)
|
223
|
-
rescue InvalidNestedValue
|
224
|
-
errors.add(attribute, :invalid_nested)
|
225
|
-
rescue InvalidValue
|
226
|
-
errors.add(attribute, :invalid,
|
227
|
-
type: I18n.translate("#{i18n_scope}.types.#{type.to_s}"))
|
228
|
-
rescue MissingValue
|
229
|
-
errors.add(attribute, :missing)
|
197
|
+
filter.default if filter.has_default?
|
230
198
|
end
|
231
199
|
end
|
232
|
-
private validator
|
233
200
|
end
|
234
|
-
private_class_method :set_up_validator
|
235
201
|
end
|
236
202
|
end
|