active_interaction 0.1.2 → 0.1.3
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 +15 -0
- data/CHANGELOG.md +10 -1
- data/README.md +70 -58
- data/lib/active_interaction.rb +1 -1
- data/lib/active_interaction/base.rb +47 -39
- data/lib/active_interaction/filter_method.rb +1 -1
- data/lib/active_interaction/filters/array_filter.rb +3 -3
- data/lib/active_interaction/filters/date_time_filter.rb +2 -1
- data/lib/active_interaction/filters/file_filter.rb +2 -2
- data/lib/active_interaction/filters/hash_filter.rb +4 -4
- data/lib/active_interaction/filters/model_filter.rb +2 -1
- data/lib/active_interaction/filters/time_filter.rb +3 -3
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/base_spec.rb +8 -6
- data/spec/active_interaction/filters/array_filter_spec.rb +3 -3
- data/spec/active_interaction/filters/hash_filter_spec.rb +3 -3
- data/spec/active_interaction/filters/model_filter_spec.rb +3 -3
- data/spec/active_interaction/filters/time_filter_spec.rb +20 -6
- data/spec/active_interaction/integration/array_interaction_spec.rb +1 -1
- data/spec/active_interaction/integration/hash_interaction_spec.rb +1 -1
- data/spec/active_interaction/integration/model_interaction_spec.rb +1 -1
- data/spec/active_interaction/overload_hash_spec.rb +6 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/interactions.rb +7 -6
- metadata +51 -74
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NWZlM2U4M2ZiMTYwNjRkOTRkNjQwYWM4OWU5OGM2ZWFhY2FjNDBhMA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjRjODdkZTczNWM0MWY1ZTQxMWY5NDUxMTcwNDRhYTI2YWNhYTY1MA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YWIxYmE0YzhjYzQwNGY1ZjMxY2M5ZTYyODEwYzA5N2UyYWM1ZjY5ZDIyN2Vk
|
10
|
+
MTM3YzY5YzZkOGQyZjZmZGQzY2VlNDJkNjBhMjQ1YzQyNGRiMmY3NzRhMDc1
|
11
|
+
MTQ0ZWM5Y2VhMGMxZTY1MjU4Nzg3YjQ5MzU2ZmNmMDhmZTdjNzY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDQ3MDUwNDVmMDA3MmIwZDJiZmE4NDYxYTQ5ODIyMjY4ZmYwYTgwMDllYjhi
|
14
|
+
YjZjNWNhODA2NWFhNjA0ZjY0ODliMTBhOWU3YTUzZDc5YTkyNWVmYjI2MDBl
|
15
|
+
ZGI2Y2UxYjhhYjVjYTVmM2RhYjBlOTBiMWZlZDdmMjQwZmRjYWE=
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
|
+
# Master
|
2
|
+
|
3
|
+
# 0.1.3
|
4
|
+
|
5
|
+
- Fix bug that prevented `attr_accessor`s from working.
|
6
|
+
- Handle unconfigured timezones.
|
7
|
+
- Use RDoc as YARD's Markdown provider instead of kramdown.
|
8
|
+
|
1
9
|
# 0.1.2
|
2
10
|
|
3
|
-
- `execute` will now have the filtered version of the values passed
|
11
|
+
- `execute` will now have the filtered version of the values passed
|
12
|
+
to `run` or `run!` as was intended.
|
4
13
|
|
5
14
|
# 0.1.1
|
6
15
|
|
data/README.md
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
# ActiveInteraction
|
2
2
|
|
3
|
-
[![Gem Version][]]
|
4
|
-
[![Build Status][]]
|
5
|
-
[![Coverage Status][]]
|
6
|
-
[![Code Climate][]]
|
7
|
-
[![Dependency Status][]]
|
3
|
+
[![Gem Version][]][1]
|
4
|
+
[![Build Status][]][2]
|
5
|
+
[![Coverage Status][]][3]
|
6
|
+
[![Code Climate][]][4]
|
7
|
+
[![Dependency Status][]][5]
|
8
8
|
|
9
|
-
At first it seemed alright. A little business logic in a controller
|
10
|
-
wasn't going to hurt anything. Then one day you wake up
|
11
|
-
by fat models and
|
12
|
-
corner, you can't help but wonder how it came
|
9
|
+
At first it seemed alright. A little business logic in a controller
|
10
|
+
or model wasn't going to hurt anything. Then one day you wake up
|
11
|
+
and you're surrounded by fat models and unwieldy controllers. Curled
|
12
|
+
up and crying in the corner, you can't help but wonder how it came
|
13
|
+
to this.
|
13
14
|
|
14
|
-
Take back control. Slim down models and wrangle monstrous controller
|
15
|
-
with ActiveInteraction.
|
15
|
+
Take back control. Slim down models and wrangle monstrous controller
|
16
|
+
methods with ActiveInteraction.
|
16
17
|
|
17
18
|
## Installation
|
18
19
|
|
@@ -20,31 +21,32 @@ This project uses [semantic versioning][].
|
|
20
21
|
|
21
22
|
Add it to your Gemfile:
|
22
23
|
|
23
|
-
|
24
|
-
gem 'active_interaction', '~> 0.1.
|
25
|
-
|
24
|
+
```ruby
|
25
|
+
gem 'active_interaction', '~> 0.1.3'
|
26
|
+
```
|
26
27
|
|
27
28
|
And then execute:
|
28
29
|
|
29
|
-
|
30
|
+
```sh
|
30
31
|
$ bundle
|
31
|
-
|
32
|
+
```
|
32
33
|
|
33
|
-
Or install it yourself
|
34
|
+
Or install it yourself with:
|
34
35
|
|
35
|
-
|
36
|
+
```sh
|
36
37
|
$ gem install active_interaction
|
37
|
-
|
38
|
+
```
|
38
39
|
|
39
40
|
## What do I get?
|
40
41
|
|
41
|
-
ActiveInteraction::Base lets you create interaction models. These
|
42
|
-
that certain options are provided and that those
|
43
|
-
want them in. If the options are valid
|
44
|
-
|
42
|
+
ActiveInteraction::Base lets you create interaction models. These
|
43
|
+
models ensure that certain options are provided and that those
|
44
|
+
options are in the format you want them in. If the options are valid
|
45
|
+
it will call `execute`, store the return value of that method in
|
46
|
+
`result`, and return an instance of your ActiveInteraction::Base
|
45
47
|
subclass. Let's looks at a simple example:
|
46
48
|
|
47
|
-
|
49
|
+
```ruby
|
48
50
|
# Define an interaction that signs up a user.
|
49
51
|
class UserSignup < ActiveInteraction::Base
|
50
52
|
# required
|
@@ -56,11 +58,14 @@ class UserSignup < ActiveInteraction::Base
|
|
56
58
|
# ActiveRecord validations
|
57
59
|
validates :email, format: EMAIL_REGEX
|
58
60
|
|
59
|
-
# The execute method is called only if the options validate. It
|
60
|
-
# business action. The return value will be stored in
|
61
|
+
# The execute method is called only if the options validate. It
|
62
|
+
# does your business action. The return value will be stored in
|
63
|
+
# `result`.
|
61
64
|
def execute
|
62
65
|
user = User.create!(email: email, name: name)
|
63
|
-
|
66
|
+
if newsletter_subscribe
|
67
|
+
NewsletterSubscriptions.create(email: email, user_id: user.id)
|
68
|
+
end
|
64
69
|
UserMailer.async(:deliver_welcome, user.id)
|
65
70
|
user
|
66
71
|
end
|
@@ -81,45 +86,46 @@ def create
|
|
81
86
|
render action: :new
|
82
87
|
end
|
83
88
|
end
|
84
|
-
|
89
|
+
```
|
85
90
|
|
86
|
-
You may have noticed that ActiveInteraction::Base quacks like
|
87
|
-
It can use validations from your Rails application
|
88
|
-
`valid?`. Any errors are added to
|
89
|
-
model.
|
91
|
+
You may have noticed that ActiveInteraction::Base quacks like
|
92
|
+
ActiveRecord::Base. It can use validations from your Rails application
|
93
|
+
and check option validity with `valid?`. Any errors are added to
|
94
|
+
`errors` which works exactly like an ActiveRecord model.
|
90
95
|
|
91
96
|
## How do I call an interaction?
|
92
97
|
|
93
|
-
There are two way to call an interaction. Given UserSignup, you can
|
98
|
+
There are two way to call an interaction. Given UserSignup, you can
|
99
|
+
do this:
|
94
100
|
|
95
|
-
|
101
|
+
```ruby
|
96
102
|
outcome = UserSignup.run(params)
|
97
103
|
if outcome.valid?
|
98
104
|
# Do something with outcome.result...
|
99
105
|
else
|
100
106
|
# Do something with outcome.errors...
|
101
107
|
end
|
102
|
-
|
108
|
+
```
|
103
109
|
|
104
110
|
Or, you can do this:
|
105
111
|
|
106
|
-
|
112
|
+
```ruby
|
107
113
|
result = UserSignup.run!(params)
|
108
114
|
# Either returns the result of execute,
|
109
115
|
# or raises ActiveInteraction::InteractionInvalid
|
110
|
-
|
116
|
+
```
|
111
117
|
|
112
118
|
## What can I pass to an interaction?
|
113
119
|
|
114
120
|
Interactions only accept a Hash for `run` and `run!`.
|
115
121
|
|
116
|
-
|
122
|
+
```ruby
|
117
123
|
# A user comments on an article
|
118
124
|
class CreateComment < ActiveInteraction::Base
|
119
125
|
model :article, :user
|
120
126
|
string :comment
|
121
127
|
|
122
|
-
validates :comment, length: {maximum: 500}
|
128
|
+
validates :comment, length: { maximum: 500 }
|
123
129
|
|
124
130
|
def execute; ...; end
|
125
131
|
end
|
@@ -131,21 +137,21 @@ def somewhere
|
|
131
137
|
user: current_user
|
132
138
|
)
|
133
139
|
end
|
134
|
-
|
140
|
+
```
|
135
141
|
|
136
142
|
## How do I define an interaction?
|
137
143
|
|
138
144
|
1. Subclass ActiveInteraction::Base
|
139
145
|
|
140
|
-
|
146
|
+
```ruby
|
141
147
|
class YourInteraction < ActiveInteraction::Base
|
142
148
|
# ...
|
143
149
|
end
|
144
|
-
|
150
|
+
```
|
145
151
|
|
146
152
|
2. Define your attributes:
|
147
153
|
|
148
|
-
|
154
|
+
```ruby
|
149
155
|
string :name, :state
|
150
156
|
integer :age
|
151
157
|
boolean :is_special
|
@@ -159,13 +165,13 @@ end
|
|
159
165
|
end
|
160
166
|
date :arrives_on, default: Date.today
|
161
167
|
date :departs_on, default: Date.tomorrow
|
162
|
-
|
168
|
+
```
|
163
169
|
|
164
170
|
3. Use any additional validations you need:
|
165
171
|
|
166
|
-
|
167
|
-
validates :name, length: {maximum: 10}
|
168
|
-
validates :state, inclusion: {in: %w(AL AK AR ... WY)}
|
172
|
+
```ruby
|
173
|
+
validates :name, length: { maximum: 10 }
|
174
|
+
validates :state, inclusion: { in: %w(AL AK AR ... WY) }
|
169
175
|
validate arrives_before_departs
|
170
176
|
|
171
177
|
private
|
@@ -175,28 +181,34 @@ end
|
|
175
181
|
errors.add(:departs_on, 'must come after the arrival time')
|
176
182
|
end
|
177
183
|
end
|
178
|
-
|
184
|
+
```
|
179
185
|
|
180
186
|
4. Define your execute method. It can return whatever you like:
|
181
187
|
|
182
|
-
|
188
|
+
```ruby
|
183
189
|
def execute
|
184
190
|
record = do_thing(...)
|
185
191
|
# ...
|
186
192
|
record
|
187
193
|
end
|
188
|
-
|
194
|
+
```
|
189
195
|
|
190
|
-
|
196
|
+
Check out the [documentation][] for a full list of methods.
|
191
197
|
|
192
198
|
## Credits
|
193
199
|
|
194
200
|
This project was inspired by the fantastic work done in [Mutations][].
|
195
201
|
|
196
|
-
[
|
197
|
-
[
|
198
|
-
[
|
199
|
-
[
|
200
|
-
[
|
201
|
-
[
|
202
|
-
[
|
202
|
+
[1]: https://badge.fury.io/rb/active_interaction "Gem Version"
|
203
|
+
[2]: https://travis-ci.org/orgsync/active_interaction "Build Status"
|
204
|
+
[3]: https://coveralls.io/r/orgsync/active_interaction "Coverage Status"
|
205
|
+
[4]: https://codeclimate.com/github/orgsync/active_interaction "Code Climate"
|
206
|
+
[5]: https://gemnasium.com/orgsync/active_interaction "Dependency Status"
|
207
|
+
[build status]: https://travis-ci.org/orgsync/active_interaction.png
|
208
|
+
[code climate]: https://codeclimate.com/github/orgsync/active_interaction.png
|
209
|
+
[coverage status]: https://coveralls.io/repos/orgsync/active_interaction/badge.png
|
210
|
+
[dependency status]: https://gemnasium.com/orgsync/active_interaction.png
|
211
|
+
[documentation]: http://rubydoc.info/github/orgsync/active_interaction
|
212
|
+
[gem version]: https://badge.fury.io/rb/active_interaction.png
|
213
|
+
[mutations]: https://github.com/cypriss/mutations
|
214
|
+
[semantic versioning]: http://semver.org
|
data/lib/active_interaction.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
2
|
|
3
3
|
module ActiveInteraction
|
4
|
-
# @abstract Subclass and override {#execute} to implement
|
5
|
-
#
|
4
|
+
# @abstract Subclass and override {#execute} to implement a custom
|
5
|
+
# ActiveInteraction class.
|
6
6
|
#
|
7
7
|
# @example
|
8
8
|
# class ExampleInteraction < ActiveInteraction::Base
|
@@ -25,7 +25,7 @@ module ActiveInteraction
|
|
25
25
|
# p outcome.errors
|
26
26
|
# end
|
27
27
|
class Base
|
28
|
-
extend
|
28
|
+
extend ::ActiveModel::Naming
|
29
29
|
include ::ActiveModel::Conversion
|
30
30
|
include ::ActiveModel::Validations
|
31
31
|
|
@@ -57,17 +57,18 @@ module ActiveInteraction
|
|
57
57
|
end
|
58
58
|
|
59
59
|
options.each do |attribute, value|
|
60
|
-
|
61
|
-
|
60
|
+
method = "_filter__#{attribute}="
|
61
|
+
if respond_to?(method, true)
|
62
|
+
send(method, value)
|
62
63
|
else
|
63
64
|
instance_variable_set("@#{attribute}", value)
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
68
|
-
# Runs the business logic associated with the
|
69
|
-
# run when there are no validation errors. The return value is
|
70
|
-
# {#result}. This method must be overridden in the subclass.
|
69
|
+
# Runs the business logic associated with the interaction. The method is
|
70
|
+
# only run when there are no validation errors. The return value is
|
71
|
+
# placed into {#result}. This method must be overridden in the subclass.
|
71
72
|
#
|
72
73
|
# @raise [NotImplementedError] if the method is not defined.
|
73
74
|
def execute
|
@@ -81,7 +82,8 @@ module ActiveInteraction
|
|
81
82
|
#
|
82
83
|
# @macro run_attributes
|
83
84
|
#
|
84
|
-
# @return [ActiveInteraction::Base] An instance of the class `run` is
|
85
|
+
# @return [ActiveInteraction::Base] An instance of the class `run` is
|
86
|
+
# called on.
|
85
87
|
def self.run(options = {})
|
86
88
|
me = new(options)
|
87
89
|
|
@@ -105,55 +107,61 @@ module ActiveInteraction
|
|
105
107
|
end
|
106
108
|
|
107
109
|
# @private
|
108
|
-
def self.method_missing(
|
109
|
-
|
110
|
+
def self.method_missing(type, *args, &block)
|
111
|
+
filter = Filter.factory(type)
|
110
112
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
111
113
|
args.each do |attribute|
|
112
|
-
|
113
|
-
|
114
|
-
|
114
|
+
set_up_reader(attribute, filter, options, &block)
|
115
|
+
set_up_writer(attribute, filter, options, &block)
|
116
|
+
set_up_validator(attribute, type, filter, options, &block)
|
115
117
|
end
|
116
118
|
end
|
117
119
|
private_class_method :method_missing
|
118
120
|
|
119
121
|
# @private
|
120
|
-
def self.
|
121
|
-
|
122
|
-
define_method(filter_attr_writer) do |value|
|
123
|
-
filtered_value =
|
124
|
-
begin
|
125
|
-
filter.prepare(attribute, value, options, &block)
|
126
|
-
rescue InvalidValue, MissingValue
|
127
|
-
value
|
128
|
-
end
|
129
|
-
|
130
|
-
instance_variable_set("@#{attribute}", filtered_value)
|
131
|
-
end
|
132
|
-
private filter_attr_writer
|
133
|
-
|
134
|
-
attr_writer attribute
|
135
|
-
|
122
|
+
def self.set_up_reader(attribute, filter, options, &block)
|
123
|
+
default = nil
|
136
124
|
if options.has_key?(:default)
|
137
125
|
begin
|
138
|
-
|
126
|
+
default = filter.
|
127
|
+
prepare(attribute, options.delete(:default), options, &block)
|
139
128
|
rescue InvalidValue
|
140
129
|
raise InvalidDefaultValue
|
141
130
|
end
|
142
131
|
end
|
143
132
|
|
144
133
|
define_method(attribute) do
|
145
|
-
|
146
|
-
if instance_variable_defined?(
|
147
|
-
instance_variable_get(
|
134
|
+
symbol = "@#{attribute}"
|
135
|
+
if instance_variable_defined?(symbol)
|
136
|
+
instance_variable_get(symbol)
|
148
137
|
else
|
149
|
-
|
138
|
+
default
|
150
139
|
end
|
151
140
|
end
|
152
141
|
end
|
153
|
-
private_class_method :
|
142
|
+
private_class_method :set_up_reader
|
143
|
+
|
144
|
+
# @private
|
145
|
+
def self.set_up_writer(attribute, filter, options, &block)
|
146
|
+
attr_writer attribute
|
147
|
+
|
148
|
+
writer = "_filter__#{attribute}="
|
149
|
+
|
150
|
+
define_method(writer) do |value|
|
151
|
+
value =
|
152
|
+
begin
|
153
|
+
filter.prepare(attribute, value, options, &block)
|
154
|
+
rescue InvalidValue, MissingValue
|
155
|
+
value
|
156
|
+
end
|
157
|
+
instance_variable_set("@#{attribute}", value)
|
158
|
+
end
|
159
|
+
private writer
|
160
|
+
end
|
161
|
+
private_class_method :set_up_writer
|
154
162
|
|
155
163
|
# @private
|
156
|
-
def self.
|
164
|
+
def self.set_up_validator(attribute, type, filter, options, &block)
|
157
165
|
validator = "_validate__#{attribute}__#{type}"
|
158
166
|
|
159
167
|
validate validator
|
@@ -165,11 +173,11 @@ module ActiveInteraction
|
|
165
173
|
errors.add(attribute, 'is required')
|
166
174
|
rescue InvalidValue
|
167
175
|
errors.add(attribute,
|
168
|
-
|
176
|
+
"is not a valid #{type.to_s.humanize.downcase}")
|
169
177
|
end
|
170
178
|
end
|
171
179
|
private validator
|
172
180
|
end
|
173
|
-
private_class_method :
|
181
|
+
private_class_method :set_up_validator
|
174
182
|
end
|
175
183
|
end
|
@@ -7,7 +7,7 @@ module ActiveInteraction
|
|
7
7
|
@method_name, @block = method_name, block
|
8
8
|
|
9
9
|
@attribute = args.shift if args.first.is_a?(Symbol)
|
10
|
-
@options
|
10
|
+
@options = (args.first || {}).dup
|
11
11
|
|
12
12
|
if @options.include?(:default)
|
13
13
|
raise ArgumentError, ':default is not supported inside filter blocks'
|
@@ -36,10 +36,10 @@ module ActiveInteraction
|
|
36
36
|
def self.convert_values(values, &block)
|
37
37
|
return values.dup unless block_given?
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
method = get_filter_method(FilterMethods.evaluate(&block))
|
41
40
|
values.map do |value|
|
42
|
-
Filter.factory(
|
41
|
+
Filter.factory(method.method_name).
|
42
|
+
prepare(method.attribute, value, method.options, &method.block)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
private_class_method :convert_values
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module ActiveInteraction
|
2
2
|
class Base
|
3
3
|
# Creates accessors for the attributes and ensures that values passed to
|
4
|
-
# the attributes are DateTimes. String values are processed using
|
4
|
+
# the attributes are DateTimes. String values are processed using
|
5
|
+
# `parse`.
|
5
6
|
#
|
6
7
|
# @macro attribute_method_params
|
7
8
|
#
|
@@ -2,8 +2,8 @@ module ActiveInteraction
|
|
2
2
|
class Base
|
3
3
|
# Creates accessors for the attributes and ensures that values passed to
|
4
4
|
# the attributes are Files or TempFiles. It will also extract a file from
|
5
|
-
# any object with a `tempfile` method. This is useful when passing in
|
6
|
-
# params that include a file upload.
|
5
|
+
# any object with a `tempfile` method. This is useful when passing in
|
6
|
+
# Rails params that include a file upload.
|
7
7
|
#
|
8
8
|
# @macro attribute_method_params
|
9
9
|
#
|
@@ -34,10 +34,10 @@ module ActiveInteraction
|
|
34
34
|
def self.convert_values(hash, &block)
|
35
35
|
return hash unless block_given?
|
36
36
|
|
37
|
-
FilterMethods.evaluate(&block).each do |
|
38
|
-
key =
|
39
|
-
|
40
|
-
|
37
|
+
FilterMethods.evaluate(&block).each do |method|
|
38
|
+
key = method.attribute
|
39
|
+
hash[key] = Filter.factory(method.method_name).
|
40
|
+
prepare(key, hash[key], method.options, &method.block)
|
41
41
|
end
|
42
42
|
|
43
43
|
hash
|
@@ -4,7 +4,8 @@ module ActiveInteraction
|
|
4
4
|
# the attributes are the correct class.
|
5
5
|
#
|
6
6
|
# @macro attribute_method_params
|
7
|
-
# @option options [Class, String, Symbol] :class (use the attribute name)
|
7
|
+
# @option options [Class, String, Symbol] :class (use the attribute name)
|
8
|
+
# Class name used to ensure the value.
|
8
9
|
#
|
9
10
|
# @example Ensures that the class is `Account`
|
10
11
|
# model :account
|
@@ -2,8 +2,8 @@ module ActiveInteraction
|
|
2
2
|
class Base
|
3
3
|
# Creates accessors for the attributes and ensures that values passed to
|
4
4
|
# the attributes are Times. Numeric values are processed using `at`.
|
5
|
-
# Strings are processed using `parse`. If `Time.zone` is available it
|
6
|
-
# be used so that the values are time zone aware.
|
5
|
+
# Strings are processed using `parse`. If `Time.zone` is available it
|
6
|
+
# will be used so that the values are time zone aware.
|
7
7
|
#
|
8
8
|
# @macro attribute_method_params
|
9
9
|
#
|
@@ -33,7 +33,7 @@ module ActiveInteraction
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def self.time
|
36
|
-
if Time.respond_to?(:zone)
|
36
|
+
if Time.respond_to?(:zone) && !Time.zone.nil?
|
37
37
|
Time.zone
|
38
38
|
else
|
39
39
|
Time
|
@@ -30,8 +30,8 @@ describe ActiveInteraction::Base do
|
|
30
30
|
|
31
31
|
validates :thing, presence: true
|
32
32
|
|
33
|
-
def self.
|
34
|
-
|
33
|
+
def self.name
|
34
|
+
SecureRandom.hex
|
35
35
|
end
|
36
36
|
|
37
37
|
def execute
|
@@ -62,13 +62,13 @@ describe ActiveInteraction::Base do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
describe
|
65
|
+
describe 'with a filter' do
|
66
66
|
let(:described_class) { InteractionWithFilter }
|
67
67
|
|
68
68
|
context 'failing validations' do
|
69
69
|
before { options.merge!(thing: thing) }
|
70
70
|
|
71
|
-
context '
|
71
|
+
context 'with an invalid value' do
|
72
72
|
let(:thing) { 'a' }
|
73
73
|
|
74
74
|
it 'sets the attribute to the filtered value' do
|
@@ -76,7 +76,7 @@ describe ActiveInteraction::Base do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
context '
|
79
|
+
context 'without a value' do
|
80
80
|
let(:thing) { nil }
|
81
81
|
|
82
82
|
it 'sets the attribute to the filtered value' do
|
@@ -176,7 +176,9 @@ describe ActiveInteraction::Base do
|
|
176
176
|
|
177
177
|
context 'failing validations' do
|
178
178
|
it 'raises an error' do
|
179
|
-
expect {
|
179
|
+
expect {
|
180
|
+
result
|
181
|
+
}.to raise_error ActiveInteraction::InteractionInvalid
|
180
182
|
end
|
181
183
|
end
|
182
184
|
|
@@ -13,7 +13,7 @@ describe ActiveInteraction::ArrayFilter do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
context 'with
|
16
|
+
context 'with a block' do
|
17
17
|
let(:block) { Proc.new { array } }
|
18
18
|
|
19
19
|
context 'with an Array of Arrays' do
|
@@ -33,7 +33,7 @@ describe ActiveInteraction::ArrayFilter do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
context 'with
|
36
|
+
context 'with a nested block' do
|
37
37
|
let(:block) { Proc.new { array { array } } }
|
38
38
|
let(:value) { [[[]]] }
|
39
39
|
|
@@ -42,7 +42,7 @@ describe ActiveInteraction::ArrayFilter do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
context 'with
|
45
|
+
context 'with an invalid block' do
|
46
46
|
let(:block) { Proc.new { array; array } }
|
47
47
|
let(:value) { [] }
|
48
48
|
|
@@ -13,7 +13,7 @@ describe ActiveInteraction::HashFilter do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
context 'with
|
16
|
+
context 'with a block' do
|
17
17
|
let(:block) { Proc.new { hash :a } }
|
18
18
|
|
19
19
|
context 'with a Hash containing a Hash' do
|
@@ -33,7 +33,7 @@ describe ActiveInteraction::HashFilter do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
context 'with
|
36
|
+
context 'with a block with multiple filters' do
|
37
37
|
let(:block) { Proc.new { hash :a; hash :b } }
|
38
38
|
|
39
39
|
context 'with a Hash containing Hashes' do
|
@@ -45,7 +45,7 @@ describe ActiveInteraction::HashFilter do
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
context 'with
|
48
|
+
context 'with a nested block' do
|
49
49
|
let(:block) { Proc.new { hash :a do; hash :b end } }
|
50
50
|
let(:value) { { a: { b: {} } } }
|
51
51
|
|
@@ -9,7 +9,7 @@ describe ActiveInteraction::ModelFilter do
|
|
9
9
|
before { options.merge!(class: TestModel) }
|
10
10
|
|
11
11
|
describe '.prepare(key, value, options = {}, &block)' do
|
12
|
-
shared_examples '
|
12
|
+
shared_examples 'type checking' do
|
13
13
|
context 'with the right class' do
|
14
14
|
let(:value) { TestModel.new }
|
15
15
|
|
@@ -20,11 +20,11 @@ describe ActiveInteraction::ModelFilter do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'with options[:class] as a Class' do
|
23
|
-
include_examples '
|
23
|
+
include_examples 'type checking'
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'with options[:class] as a valid String' do
|
27
|
-
include_examples '
|
27
|
+
include_examples 'type checking'
|
28
28
|
|
29
29
|
before { options.merge!(class: options[:class].to_s) }
|
30
30
|
end
|
@@ -14,7 +14,7 @@ describe ActiveInteraction::TimeFilter do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
shared_examples 'conversion' do
|
17
|
-
context 'with a
|
17
|
+
context 'with a Float' do
|
18
18
|
let(:value) { rand }
|
19
19
|
|
20
20
|
it 'converts the Float' do
|
@@ -52,14 +52,28 @@ describe ActiveInteraction::TimeFilter do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
context 'with Time.zone' do
|
55
|
-
|
55
|
+
context 'as nil' do
|
56
|
+
include_examples 'conversion'
|
57
|
+
|
58
|
+
before do
|
59
|
+
allow(Time).to receive(:zone).and_return(nil)
|
60
|
+
end
|
56
61
|
|
57
|
-
|
58
|
-
|
62
|
+
after do
|
63
|
+
expect(Time).to have_received(:zone).once.with(no_args)
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
|
-
|
62
|
-
|
67
|
+
context 'as Time' do
|
68
|
+
include_examples 'conversion'
|
69
|
+
|
70
|
+
before do
|
71
|
+
allow(Time).to receive(:zone).and_return(Time)
|
72
|
+
end
|
73
|
+
|
74
|
+
after do
|
75
|
+
expect(Time).to have_received(:zone).twice.with(no_args)
|
76
|
+
end
|
63
77
|
end
|
64
78
|
end
|
65
79
|
end
|
@@ -34,7 +34,12 @@ describe ActiveInteraction::OverloadHash do
|
|
34
34
|
with(:hash, *arguments)
|
35
35
|
end
|
36
36
|
|
37
|
-
it 'passes the block to method_missing'
|
37
|
+
it 'passes the block to method_missing' do
|
38
|
+
allow(subject).to receive(:method_missing) do |*, &other_block|
|
39
|
+
expect(other_block).to equal block
|
40
|
+
end
|
41
|
+
hash(&block)
|
42
|
+
end
|
38
43
|
end
|
39
44
|
end
|
40
45
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,15 +4,16 @@ shared_context 'interactions' do
|
|
4
4
|
let(:result) { outcome.result }
|
5
5
|
end
|
6
6
|
|
7
|
-
shared_examples_for 'an interaction' do |type,
|
7
|
+
shared_examples_for 'an interaction' do |type, generator, filter_options = {}|
|
8
8
|
include_context 'interactions'
|
9
9
|
|
10
10
|
let(:described_class) do
|
11
11
|
Class.new(ActiveInteraction::Base) do
|
12
12
|
send(type, :required, filter_options)
|
13
13
|
send(type, :optional, filter_options.merge(allow_nil: true))
|
14
|
-
send(type, :default, filter_options.merge(default:
|
15
|
-
send(type, :nil_default,
|
14
|
+
send(type, :default, filter_options.merge(default: generator.call))
|
15
|
+
send(type, :nil_default,
|
16
|
+
filter_options.merge(allow_nil: true, default: nil))
|
16
17
|
|
17
18
|
def execute
|
18
19
|
{
|
@@ -32,7 +33,7 @@ shared_examples_for 'an interaction' do |type, value_lambda, filter_options = {}
|
|
32
33
|
end
|
33
34
|
|
34
35
|
context 'with options[:required]' do
|
35
|
-
let(:required) {
|
36
|
+
let(:required) { generator.call }
|
36
37
|
|
37
38
|
before { options.merge!(required: required) }
|
38
39
|
|
@@ -57,7 +58,7 @@ shared_examples_for 'an interaction' do |type, value_lambda, filter_options = {}
|
|
57
58
|
end
|
58
59
|
|
59
60
|
context 'with options[:optional]' do
|
60
|
-
let(:optional) {
|
61
|
+
let(:optional) { generator.call }
|
61
62
|
|
62
63
|
before { options.merge!(optional: optional) }
|
63
64
|
|
@@ -67,7 +68,7 @@ shared_examples_for 'an interaction' do |type, value_lambda, filter_options = {}
|
|
67
68
|
end
|
68
69
|
|
69
70
|
context 'with options[:default]' do
|
70
|
-
let(:default) {
|
71
|
+
let(:default) { generator.call }
|
71
72
|
|
72
73
|
before { options.merge!(default: default) }
|
73
74
|
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_interaction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.1.2
|
4
|
+
version: 0.1.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Aaron Lasseigne
|
@@ -10,152 +9,134 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: activemodel
|
17
|
-
type: :runtime
|
18
16
|
requirement: !ruby/object:Gem::Requirement
|
19
17
|
requirements:
|
20
18
|
- - ! '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: 3.0.0
|
23
|
-
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
24
23
|
version_requirements: !ruby/object:Gem::Requirement
|
25
24
|
requirements:
|
26
25
|
- - ! '>='
|
27
26
|
- !ruby/object:Gem::Version
|
28
27
|
version: 3.0.0
|
29
|
-
none: false
|
30
|
-
prerelease: false
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: bundler
|
33
|
-
type: :development
|
34
30
|
requirement: !ruby/object:Gem::Requirement
|
35
31
|
requirements:
|
36
32
|
- - ~>
|
37
33
|
- !ruby/object:Gem::Version
|
38
34
|
version: '1.3'
|
39
|
-
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
40
37
|
version_requirements: !ruby/object:Gem::Requirement
|
41
38
|
requirements:
|
42
39
|
- - ~>
|
43
40
|
- !ruby/object:Gem::Version
|
44
41
|
version: '1.3'
|
45
|
-
none: false
|
46
|
-
prerelease: false
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: coveralls
|
49
|
-
type: :development
|
50
44
|
requirement: !ruby/object:Gem::Requirement
|
51
45
|
requirements:
|
52
46
|
- - ~>
|
53
47
|
- !ruby/object:Gem::Version
|
54
48
|
version: '0.6'
|
55
|
-
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
56
51
|
version_requirements: !ruby/object:Gem::Requirement
|
57
52
|
requirements:
|
58
53
|
- - ~>
|
59
54
|
- !ruby/object:Gem::Version
|
60
55
|
version: '0.6'
|
61
|
-
none: false
|
62
|
-
prerelease: false
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
57
|
name: guard-rspec
|
65
|
-
type: :development
|
66
58
|
requirement: !ruby/object:Gem::Requirement
|
67
59
|
requirements:
|
68
60
|
- - ~>
|
69
61
|
- !ruby/object:Gem::Version
|
70
62
|
version: '3.0'
|
71
|
-
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
72
65
|
version_requirements: !ruby/object:Gem::Requirement
|
73
66
|
requirements:
|
74
67
|
- - ~>
|
75
68
|
- !ruby/object:Gem::Version
|
76
69
|
version: '3.0'
|
77
|
-
none: false
|
78
|
-
prerelease: false
|
79
70
|
- !ruby/object:Gem::Dependency
|
80
|
-
name:
|
81
|
-
type: :development
|
71
|
+
name: rake
|
82
72
|
requirement: !ruby/object:Gem::Requirement
|
83
73
|
requirements:
|
84
74
|
- - ~>
|
85
75
|
- !ruby/object:Gem::Version
|
86
|
-
version: '
|
87
|
-
|
76
|
+
version: '10.1'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
88
79
|
version_requirements: !ruby/object:Gem::Requirement
|
89
80
|
requirements:
|
90
81
|
- - ~>
|
91
82
|
- !ruby/object:Gem::Version
|
92
|
-
version: '
|
93
|
-
none: false
|
94
|
-
prerelease: false
|
83
|
+
version: '10.1'
|
95
84
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
97
|
-
type: :development
|
85
|
+
name: rb-fsevent
|
98
86
|
requirement: !ruby/object:Gem::Requirement
|
99
87
|
requirements:
|
100
88
|
- - ~>
|
101
89
|
- !ruby/object:Gem::Version
|
102
|
-
version: '
|
103
|
-
|
90
|
+
version: '0.9'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
104
93
|
version_requirements: !ruby/object:Gem::Requirement
|
105
94
|
requirements:
|
106
95
|
- - ~>
|
107
96
|
- !ruby/object:Gem::Version
|
108
|
-
version: '
|
109
|
-
none: false
|
110
|
-
prerelease: false
|
97
|
+
version: '0.9'
|
111
98
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
113
|
-
type: :development
|
99
|
+
name: rdoc
|
114
100
|
requirement: !ruby/object:Gem::Requirement
|
115
101
|
requirements:
|
116
102
|
- - ~>
|
117
103
|
- !ruby/object:Gem::Version
|
118
|
-
version: '0
|
119
|
-
|
104
|
+
version: '4.0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
120
107
|
version_requirements: !ruby/object:Gem::Requirement
|
121
108
|
requirements:
|
122
109
|
- - ~>
|
123
110
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0
|
125
|
-
none: false
|
126
|
-
prerelease: false
|
111
|
+
version: '4.0'
|
127
112
|
- !ruby/object:Gem::Dependency
|
128
113
|
name: rspec
|
129
|
-
type: :development
|
130
114
|
requirement: !ruby/object:Gem::Requirement
|
131
115
|
requirements:
|
132
116
|
- - ~>
|
133
117
|
- !ruby/object:Gem::Version
|
134
118
|
version: '2.14'
|
135
|
-
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
136
121
|
version_requirements: !ruby/object:Gem::Requirement
|
137
122
|
requirements:
|
138
123
|
- - ~>
|
139
124
|
- !ruby/object:Gem::Version
|
140
125
|
version: '2.14'
|
141
|
-
none: false
|
142
|
-
prerelease: false
|
143
126
|
- !ruby/object:Gem::Dependency
|
144
127
|
name: yard
|
145
|
-
type: :development
|
146
128
|
requirement: !ruby/object:Gem::Requirement
|
147
129
|
requirements:
|
148
130
|
- - ~>
|
149
131
|
- !ruby/object:Gem::Version
|
150
132
|
version: '0.8'
|
151
|
-
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
152
135
|
version_requirements: !ruby/object:Gem::Requirement
|
153
136
|
requirements:
|
154
137
|
- - ~>
|
155
138
|
- !ruby/object:Gem::Version
|
156
139
|
version: '0.8'
|
157
|
-
none: false
|
158
|
-
prerelease: false
|
159
140
|
description: Manage application specific business logic.
|
160
141
|
email:
|
161
142
|
- aaron.lasseigne@gmail.com
|
@@ -164,6 +145,25 @@ executables: []
|
|
164
145
|
extensions: []
|
165
146
|
extra_rdoc_files: []
|
166
147
|
files:
|
148
|
+
- lib/active_interaction/base.rb
|
149
|
+
- lib/active_interaction/errors.rb
|
150
|
+
- lib/active_interaction/filter.rb
|
151
|
+
- lib/active_interaction/filter_method.rb
|
152
|
+
- lib/active_interaction/filter_methods.rb
|
153
|
+
- lib/active_interaction/filters/array_filter.rb
|
154
|
+
- lib/active_interaction/filters/boolean_filter.rb
|
155
|
+
- lib/active_interaction/filters/date_filter.rb
|
156
|
+
- lib/active_interaction/filters/date_time_filter.rb
|
157
|
+
- lib/active_interaction/filters/file_filter.rb
|
158
|
+
- lib/active_interaction/filters/float_filter.rb
|
159
|
+
- lib/active_interaction/filters/hash_filter.rb
|
160
|
+
- lib/active_interaction/filters/integer_filter.rb
|
161
|
+
- lib/active_interaction/filters/model_filter.rb
|
162
|
+
- lib/active_interaction/filters/string_filter.rb
|
163
|
+
- lib/active_interaction/filters/time_filter.rb
|
164
|
+
- lib/active_interaction/overload_hash.rb
|
165
|
+
- lib/active_interaction/version.rb
|
166
|
+
- lib/active_interaction.rb
|
167
167
|
- spec/active_interaction/base_spec.rb
|
168
168
|
- spec/active_interaction/filter_method_spec.rb
|
169
169
|
- spec/active_interaction/filter_methods_spec.rb
|
@@ -194,31 +194,13 @@ files:
|
|
194
194
|
- spec/spec_helper.rb
|
195
195
|
- spec/support/filters.rb
|
196
196
|
- spec/support/interactions.rb
|
197
|
-
- lib/active_interaction/base.rb
|
198
|
-
- lib/active_interaction/errors.rb
|
199
|
-
- lib/active_interaction/filter.rb
|
200
|
-
- lib/active_interaction/filter_method.rb
|
201
|
-
- lib/active_interaction/filter_methods.rb
|
202
|
-
- lib/active_interaction/filters/array_filter.rb
|
203
|
-
- lib/active_interaction/filters/boolean_filter.rb
|
204
|
-
- lib/active_interaction/filters/date_filter.rb
|
205
|
-
- lib/active_interaction/filters/date_time_filter.rb
|
206
|
-
- lib/active_interaction/filters/file_filter.rb
|
207
|
-
- lib/active_interaction/filters/float_filter.rb
|
208
|
-
- lib/active_interaction/filters/hash_filter.rb
|
209
|
-
- lib/active_interaction/filters/integer_filter.rb
|
210
|
-
- lib/active_interaction/filters/model_filter.rb
|
211
|
-
- lib/active_interaction/filters/string_filter.rb
|
212
|
-
- lib/active_interaction/filters/time_filter.rb
|
213
|
-
- lib/active_interaction/overload_hash.rb
|
214
|
-
- lib/active_interaction/version.rb
|
215
|
-
- lib/active_interaction.rb
|
216
197
|
- CHANGELOG.md
|
217
198
|
- LICENSE.txt
|
218
199
|
- README.md
|
219
200
|
homepage: https://github.com/orgsync/active_interaction
|
220
201
|
licenses:
|
221
202
|
- MIT
|
203
|
+
metadata: {}
|
222
204
|
post_install_message:
|
223
205
|
rdoc_options: []
|
224
206
|
require_paths:
|
@@ -228,21 +210,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
228
210
|
- - ! '>='
|
229
211
|
- !ruby/object:Gem::Version
|
230
212
|
version: 1.9.3
|
231
|
-
none: false
|
232
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
233
214
|
requirements:
|
234
215
|
- - ! '>='
|
235
216
|
- !ruby/object:Gem::Version
|
236
|
-
segments:
|
237
|
-
- 0
|
238
|
-
hash: 669983182544330814
|
239
217
|
version: '0'
|
240
|
-
none: false
|
241
218
|
requirements: []
|
242
219
|
rubyforge_project:
|
243
|
-
rubygems_version:
|
220
|
+
rubygems_version: 2.0.5
|
244
221
|
signing_key:
|
245
|
-
specification_version:
|
222
|
+
specification_version: 4
|
246
223
|
summary: Manage application specific business logic.
|
247
224
|
test_files:
|
248
225
|
- spec/active_interaction/base_spec.rb
|