active_interaction 2.1.5 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +26 -3
  4. data/lib/active_interaction.rb +1 -2
  5. data/lib/active_interaction/backports.rb +1 -0
  6. data/lib/active_interaction/base.rb +3 -2
  7. data/lib/active_interaction/concerns/active_modelable.rb +1 -0
  8. data/lib/active_interaction/concerns/active_recordable.rb +1 -0
  9. data/lib/active_interaction/concerns/hashable.rb +1 -0
  10. data/lib/active_interaction/concerns/missable.rb +1 -0
  11. data/lib/active_interaction/concerns/runnable.rb +1 -0
  12. data/lib/active_interaction/errors.rb +1 -0
  13. data/lib/active_interaction/filter.rb +16 -9
  14. data/lib/active_interaction/filter_column.rb +1 -0
  15. data/lib/active_interaction/filters/abstract_date_time_filter.rb +6 -5
  16. data/lib/active_interaction/filters/abstract_filter.rb +1 -0
  17. data/lib/active_interaction/filters/abstract_numeric_filter.rb +5 -4
  18. data/lib/active_interaction/filters/array_filter.rb +3 -2
  19. data/lib/active_interaction/filters/boolean_filter.rb +2 -1
  20. data/lib/active_interaction/filters/date_filter.rb +1 -0
  21. data/lib/active_interaction/filters/date_time_filter.rb +1 -0
  22. data/lib/active_interaction/filters/decimal_filter.rb +2 -1
  23. data/lib/active_interaction/filters/file_filter.rb +1 -0
  24. data/lib/active_interaction/filters/float_filter.rb +1 -0
  25. data/lib/active_interaction/filters/hash_filter.rb +6 -5
  26. data/lib/active_interaction/filters/integer_filter.rb +1 -0
  27. data/lib/active_interaction/filters/interface_filter.rb +2 -1
  28. data/lib/active_interaction/filters/object_filter.rb +4 -3
  29. data/lib/active_interaction/filters/string_filter.rb +2 -1
  30. data/lib/active_interaction/filters/symbol_filter.rb +2 -1
  31. data/lib/active_interaction/filters/time_filter.rb +2 -1
  32. data/lib/active_interaction/grouped_input.rb +1 -0
  33. data/lib/active_interaction/modules/input_processor.rb +1 -0
  34. data/lib/active_interaction/modules/validation.rb +4 -2
  35. data/lib/active_interaction/version.rb +2 -1
  36. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -1
  37. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -1
  38. data/spec/active_interaction/filters/array_filter_spec.rb +1 -1
  39. data/spec/active_interaction/filters/boolean_filter_spec.rb +2 -2
  40. data/spec/active_interaction/filters/date_filter_spec.rb +2 -2
  41. data/spec/active_interaction/filters/date_time_filter_spec.rb +2 -2
  42. data/spec/active_interaction/filters/decimal_filter_spec.rb +1 -1
  43. data/spec/active_interaction/filters/file_filter_spec.rb +1 -1
  44. data/spec/active_interaction/filters/float_filter_spec.rb +1 -1
  45. data/spec/active_interaction/filters/hash_filter_spec.rb +3 -3
  46. data/spec/active_interaction/filters/integer_filter_spec.rb +1 -1
  47. data/spec/active_interaction/filters/interface_filter_spec.rb +1 -1
  48. data/spec/active_interaction/filters/object_filter_spec.rb +4 -4
  49. data/spec/active_interaction/filters/string_filter_spec.rb +1 -1
  50. data/spec/active_interaction/filters/symbol_filter_spec.rb +1 -1
  51. data/spec/active_interaction/filters/time_filter_spec.rb +2 -2
  52. data/spec/active_interaction/modules/validation_spec.rb +11 -4
  53. data/spec/support/filters.rb +11 -11
  54. data/spec/support/interactions.rb +6 -0
  55. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a54101dfa80812134a34c6977fa538e23d67c7f
4
- data.tar.gz: 3a3d21348e1f37a649ca23801a1b01f5974c9399
3
+ metadata.gz: 6ab0b6acaa850b033873f57885ab405bd0617fb1
4
+ data.tar.gz: fa8014160f12647a93e6630e740a7caea0b6e866
5
5
  SHA512:
6
- metadata.gz: 04fe6f23d9235893ca47203481f9f4a7709acffebb0d8f24f3769ccfe07dc8b52133e3e82f2f1be039eaf8a4859572536c106d0bc5fffcf96fffb767c3a4226a
7
- data.tar.gz: df1cf833864649ddb7d402a3da8b657987863da264728f755657625d3cda9293c58968509608b2ae6a12831a71d91141d5c638e7650d10050c666407b0c71945
6
+ metadata.gz: 7c3ba3db8d3d3f6886e0badc849f80036d7633bdc2e4cfef8da3fcf07c556167181bd182757f0b0aae8fd9fc8d273b75a3bcf88d320310f5f7bc41ea6f8d0490
7
+ data.tar.gz: 9b0588c2945678a31fbf315bf2b44f2168d5dbfad1e4398e2c07a558f91ae0fa66ac15622a3b4b049ee103b863ed290091963098cccc1c35e74f64a361b8ee22
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [2.2.0][] (2015-12-18)
2
+
3
+ ## Added
4
+
5
+ - [#336][]: Added frozen string pragma for Ruby 2.3.
6
+
7
+ ## Changed
8
+
9
+ - [#332][]: Changed default lambdas to be evaluated in the interaction's
10
+ binding.
11
+
1
12
  # [2.1.5][] (2015-12-11)
2
13
 
3
14
  ## Added
@@ -482,6 +493,7 @@ For help upgrading to version 2, please read [the announcement post][].
482
493
 
483
494
  - Initial release.
484
495
 
496
+ [2.2.0]: https://github.com/orgsync/active_interaction/compare/v2.1.5...v2.2.0
485
497
  [2.1.5]: https://github.com/orgsync/active_interaction/compare/v2.1.4...v2.1.5
486
498
  [2.1.4]: https://github.com/orgsync/active_interaction/compare/v2.1.3...v2.1.4
487
499
  [2.1.3]: https://github.com/orgsync/active_interaction/compare/v2.1.2...v2.1.3
@@ -631,5 +643,7 @@ For help upgrading to version 2, please read [the announcement post][].
631
643
  [#311]: https://github.com/orgsync/active_interaction/issues/311
632
644
  [#320]: https://github.com/orgsync/active_interaction/issues/320
633
645
  [#330]: https://github.com/orgsync/active_interaction/pull/330
646
+ [#332]: https://github.com/orgsync/active_interaction/pull/332
647
+ [#336]: https://github.com/orgsync/active_interaction/pull/336
634
648
 
635
649
  [the announcement post]: http://devblog.orgsync.com/2015/05/06/announcing-active-interaction-2/
data/README.md CHANGED
@@ -52,6 +52,7 @@ Read more on [the project page][] or check out [the full documentation][].
52
52
  - [Advanced usage](#advanced-usage)
53
53
  - [Callbacks](#callbacks)
54
54
  - [Composition](#composition)
55
+ - [Defaults](#defaults)
55
56
  - [Descriptions](#descriptions)
56
57
  - [Errors](#errors)
57
58
  - [Forms](#forms)
@@ -66,13 +67,13 @@ Read more on [the project page][] or check out [the full documentation][].
66
67
  Add it to your Gemfile:
67
68
 
68
69
  ``` rb
69
- gem 'active_interaction', '~> 2.1'
70
+ gem 'active_interaction', '~> 2.2'
70
71
  ```
71
72
 
72
73
  Or install it manually:
73
74
 
74
75
  ``` sh
75
- $ gem install active_interaction --version '~> 2.1'
76
+ $ gem install active_interaction --version '~> 2.2'
76
77
  ```
77
78
 
78
79
  This project uses [Semantic Versioning][]. Check out [the change log][] for a
@@ -980,6 +981,28 @@ class AddAndDouble < ActiveInteraction::Base
980
981
  end
981
982
  ```
982
983
 
984
+ ### Defaults
985
+
986
+ The default value for an input can take on many different forms. Setting the
987
+ default to `nil` makes the input optional. Setting it to some value makes that
988
+ the default value for that input. Setting it to a lambda will lazily set the
989
+ default value for that input. That means the value will be computed when the
990
+ interaction is run, as opposed to when it is defined.
991
+
992
+ Lambda defaults are evaluated in the context of the interaction, so you can use
993
+ the values of other inputs in them.
994
+
995
+ ``` rb
996
+ # This input is optional.
997
+ time :a, default: nil
998
+ # This input defaults to `Time.at(123)`.
999
+ time :b, default: Time.at(123)
1000
+ # This input lazily defaults to `Time.now`.
1001
+ time :c, default: -> { Time.now }
1002
+ # This input defaults to the value of `c` plus 10 seconds.
1003
+ time :d, default: -> { c + 10 }
1004
+ ```
1005
+
983
1006
  ### Descriptions
984
1007
 
985
1008
  Use the `desc` option to provide human-readable descriptions of filters. You
@@ -1192,7 +1215,7 @@ class UpdateUser < ActiveInteraction::Base
1192
1215
 
1193
1216
  def execute
1194
1217
  user.birthday = birthday if given?(:birthday)
1195
- errors.merge!(user) unless user.save
1218
+ errors.merge!(user.errors) unless user.save
1196
1219
  user
1197
1220
  end
1198
1221
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'active_model'
4
5
 
@@ -8,8 +9,6 @@ require 'active_model'
8
9
  # @author Taylor Fausak <taylor@fausak.me>
9
10
  #
10
11
  # @since 1.0.0
11
- #
12
- # @version 2.1.5
13
12
  module ActiveInteraction
14
13
  end
15
14
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'active_support/core_ext'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'active_support/core_ext/hash/indifferent_access'
4
5
  require 'set'
@@ -251,7 +252,7 @@ module ActiveInteraction
251
252
  def populate_filters(inputs)
252
253
  self.class.filters.each do |name, filter|
253
254
  begin
254
- public_send("#{name}=", filter.clean(inputs[name]))
255
+ public_send("#{name}=", filter.clean(inputs[name], self))
255
256
  rescue InvalidValueError, MissingValueError, NoDefaultError
256
257
  # #type_check will add errors if appropriate.
257
258
  end
@@ -260,7 +261,7 @@ module ActiveInteraction
260
261
 
261
262
  def type_check
262
263
  run_callbacks(:type_check) do
263
- Validation.validate(self.class.filters, inputs).each do |error|
264
+ Validation.validate(self, self.class.filters, inputs).each do |error|
264
265
  errors.add(*error)
265
266
  end
266
267
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Implement the minimal ActiveModel interface.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Implement the minimal ActiveRecord interface.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Allow `hash` to be overridden when given arguments and/or a block.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Handle common `method_missing` functionality.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # @abstract Include and override {#execute} to implement a custom Runnable
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  #
4
5
  module ActiveInteraction
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'active_support/inflector'
4
5
 
@@ -90,15 +91,16 @@ module ActiveInteraction
90
91
  # # => ActiveInteraction::InvalidDefaultError: example: 0
91
92
  #
92
93
  # @param value [Object]
94
+ # @param context [Base, nil]
93
95
  #
94
96
  # @return [Object]
95
97
  #
96
98
  # @raise (see #cast)
97
99
  # @raise (see #default)
98
- def clean(value)
99
- value = cast(value)
100
+ def clean(value, context)
101
+ value = cast(value, context)
100
102
  if value.nil?
101
- default
103
+ default(context)
102
104
  else
103
105
  value
104
106
  end
@@ -116,17 +118,19 @@ module ActiveInteraction
116
118
  # ActiveInteraction::Filter.new(:example, default: 0).default
117
119
  # # => ActiveInteraction::InvalidDefaultError: example: 0
118
120
  #
121
+ # @param context [Base, nil]
122
+ #
119
123
  # @return (see #raw_default)
120
124
  #
121
125
  # @raise [NoDefaultError] If the default is missing.
122
126
  # @raise [InvalidDefaultError] If the default is invalid.
123
- def default
127
+ def default(context = nil)
124
128
  fail NoDefaultError, name unless default?
125
129
 
126
- value = raw_default
130
+ value = raw_default(context)
127
131
  fail InvalidValueError if value.is_a?(GroupedInput)
128
132
 
129
- cast(value)
133
+ cast(value, context)
130
134
  rescue InvalidNestedValueError => error
131
135
  raise InvalidDefaultError, "#{name}: #{value.inspect} (#{error})"
132
136
  rescue InvalidValueError, MissingValueError
@@ -159,6 +163,7 @@ module ActiveInteraction
159
163
  end
160
164
 
161
165
  # @param value [Object]
166
+ # @param _interaction [Base, nil]
162
167
  #
163
168
  # @return [Object]
164
169
  #
@@ -167,7 +172,7 @@ module ActiveInteraction
167
172
  # @raise [InvalidValueError] If the value is invalid.
168
173
  #
169
174
  # @private
170
- def cast(value)
175
+ def cast(value, _interaction)
171
176
  case value
172
177
  when NilClass
173
178
  fail MissingValueError, name unless default?
@@ -205,12 +210,14 @@ module ActiveInteraction
205
210
  "(Object doesn't support #inspect)"
206
211
  end
207
212
 
213
+ # @param context [Base, nil]
214
+ #
208
215
  # @return [Object]
209
- def raw_default
216
+ def raw_default(context)
210
217
  value = options.fetch(:default)
211
218
 
212
219
  if value.is_a?(Proc)
213
- value.call
220
+ context.instance_exec(&value)
214
221
  else
215
222
  value
216
223
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # A minimal implementation of an `ActiveRecord::ConnectionAdapters::Column`.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # @abstract
@@ -11,12 +12,12 @@ module ActiveInteraction
11
12
  alias_method :_cast, :cast
12
13
  private :_cast
13
14
 
14
- def cast(value)
15
+ def cast(value, context)
15
16
  case value
16
17
  when String
17
- convert(value)
18
+ convert(value, context)
18
19
  when GroupedInput
19
- convert(stringify(value))
20
+ convert(stringify(value), context)
20
21
  when *klasses
21
22
  value
22
23
  else
@@ -30,7 +31,7 @@ module ActiveInteraction
30
31
 
31
32
  private
32
33
 
33
- def convert(value)
34
+ def convert(value, context)
34
35
  if format?
35
36
  klass.strptime(value, format)
36
37
  else
@@ -38,7 +39,7 @@ module ActiveInteraction
38
39
  (fail ArgumentError, "no time information in #{value.inspect}")
39
40
  end
40
41
  rescue ArgumentError
41
- _cast(value)
42
+ _cast(value, context)
42
43
  end
43
44
 
44
45
  # @return [String]
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # @abstract
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # @abstract
@@ -10,12 +11,12 @@ module ActiveInteraction
10
11
  alias_method :_cast, :cast
11
12
  private :_cast
12
13
 
13
- def cast(value)
14
+ def cast(value, context)
14
15
  case value
15
16
  when klass
16
17
  value
17
18
  when Numeric, String
18
- convert(value)
19
+ convert(value, context)
19
20
  else
20
21
  super
21
22
  end
@@ -27,10 +28,10 @@ module ActiveInteraction
27
28
 
28
29
  private
29
30
 
30
- def convert(value)
31
+ def convert(value, context)
31
32
  Kernel.public_send(klass.name, value)
32
33
  rescue ArgumentError
33
- _cast(value)
34
+ _cast(value, context)
34
35
  end
35
36
  end
36
37
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -27,13 +28,13 @@ module ActiveInteraction
27
28
 
28
29
  register :array
29
30
 
30
- def cast(value)
31
+ def cast(value, context)
31
32
  case value
32
33
  when *classes
33
34
  return value if filters.empty?
34
35
 
35
36
  filter = filters.values.first
36
- value.map { |e| filter.clean(e) }
37
+ value.map { |e| filter.clean(e, context) }
37
38
  else
38
39
  super
39
40
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -18,7 +19,7 @@ module ActiveInteraction
18
19
  class BooleanFilter < Filter
19
20
  register :boolean
20
21
 
21
- def cast(value)
22
+ def cast(value, _interaction)
22
23
  case value
23
24
  when FalseClass, '0', /\Afalse\z/i
24
25
  false
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bigdecimal'
4
5
 
@@ -21,7 +22,7 @@ module ActiveInteraction
21
22
  class DecimalFilter < AbstractNumericFilter
22
23
  register :decimal
23
24
 
24
- def cast(value)
25
+ def cast(value, _interaction)
25
26
  case value
26
27
  when Numeric
27
28
  BigDecimal.new(value, digits)
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -25,14 +26,14 @@ module ActiveInteraction
25
26
 
26
27
  register :hash
27
28
 
28
- def cast(value)
29
+ def cast(value, context)
29
30
  case value
30
31
  when Hash
31
32
  value = value.with_indifferent_access
32
33
  initial = strip? ? ActiveSupport::HashWithIndifferentAccess.new : value
33
34
 
34
35
  filters.each_with_object(initial) do |(name, filter), h|
35
- clean_value(h, name.to_s, filter, value)
36
+ clean_value(h, name.to_s, filter, value, context)
36
37
  end
37
38
  else
38
39
  super
@@ -51,13 +52,13 @@ module ActiveInteraction
51
52
 
52
53
  private
53
54
 
54
- def clean_value(h, name, filter, value)
55
- h[name] = filter.clean(value[name])
55
+ def clean_value(h, name, filter, value, context)
56
+ h[name] = filter.clean(value[name], context)
56
57
  rescue InvalidValueError, MissingValueError
57
58
  raise InvalidNestedValueError.new(name, value[name])
58
59
  end
59
60
 
60
- def raw_default
61
+ def raw_default(*)
61
62
  value = super
62
63
 
63
64
  if value.is_a?(Hash) && !value.empty?
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -21,7 +22,7 @@ module ActiveInteraction
21
22
  class InterfaceFilter < Filter
22
23
  register :interface
23
24
 
24
- def cast(value)
25
+ def cast(value, _interaction)
25
26
  matches?(value) ? value : super
26
27
  end
27
28
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -20,16 +21,16 @@ module ActiveInteraction
20
21
  class ObjectFilter < Filter
21
22
  register :object
22
23
 
23
- def cast(value, reconstantize = true)
24
+ def cast(value, context, reconstantize = true)
24
25
  @klass ||= klass
25
26
 
26
27
  if matches?(value)
27
28
  value
28
29
  else
29
- return super(value) unless reconstantize
30
+ return super(value, context) unless reconstantize
30
31
 
31
32
  @klass = klass
32
- cast(value, false)
33
+ cast(value, context, false)
33
34
  end
34
35
  end
35
36
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -20,7 +21,7 @@ module ActiveInteraction
20
21
  class StringFilter < Filter
21
22
  register :string
22
23
 
23
- def cast(value)
24
+ def cast(value, _interaction)
24
25
  case value
25
26
  when String
26
27
  strip? ? value.strip : value
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -16,7 +17,7 @@ module ActiveInteraction
16
17
  class SymbolFilter < Filter
17
18
  register :symbol
18
19
 
19
- def cast(value)
20
+ def cast(value, _interaction)
20
21
  case value
21
22
  when Symbol
22
23
  value
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  class Base
@@ -34,7 +35,7 @@ module ActiveInteraction
34
35
  super
35
36
  end
36
37
 
37
- def cast(value)
38
+ def cast(value, _interaction)
38
39
  case value
39
40
  when Numeric
40
41
  klass.at(value)
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'ostruct'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Groups inputs ending in "(*N*i)" into {GroupedInput}.
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module ActiveInteraction
4
5
  # Validates inputs using filters.
@@ -6,12 +7,13 @@ module ActiveInteraction
6
7
  # @private
7
8
  module Validation
8
9
  class << self
10
+ # @param context [Base]
9
11
  # @param filters [Hash{Symbol => Filter}]
10
12
  # @param inputs [Hash{Symbol => Object}]
11
- def validate(filters, inputs)
13
+ def validate(context, filters, inputs)
12
14
  filters.each_with_object([]) do |(name, filter), errors|
13
15
  begin
14
- filter.cast(inputs[name])
16
+ filter.cast(inputs[name], context)
15
17
  rescue InvalidNestedValueError,
16
18
  InvalidValueError,
17
19
  MissingValueError => e
@@ -1,9 +1,10 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  #
4
5
  module ActiveInteraction
5
6
  # The version number.
6
7
  #
7
8
  # @return [Gem::Version]
8
- VERSION = Gem::Version.new('2.1.5')
9
+ VERSION = Gem::Version.new('2.2.0')
9
10
  end
@@ -9,7 +9,7 @@ describe ActiveInteraction::AbstractDateTimeFilter, :filter do
9
9
  let(:value) { nil }
10
10
 
11
11
  it 'raises an error' do
12
- expect { filter.cast(value) }.to raise_error NameError
12
+ expect { filter.cast(value, nil) }.to raise_error NameError
13
13
  end
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ describe ActiveInteraction::AbstractNumericFilter, :filter do
9
9
  let(:value) { nil }
10
10
 
11
11
  it 'raises an error' do
12
- expect { filter.cast(value) }.to raise_error NameError
12
+ expect { filter.cast(value, nil) }.to raise_error NameError
13
13
  end
14
14
  end
15
15
  end
@@ -36,7 +36,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
36
36
  end
37
37
 
38
38
  describe '#cast' do
39
- let(:result) { filter.cast(value) }
39
+ let(:result) { filter.cast(value, nil) }
40
40
 
41
41
  context 'with an Array' do
42
42
  let(:value) { [] }
@@ -10,7 +10,7 @@ describe ActiveInteraction::BooleanFilter, :filter do
10
10
  context 'falsey' do
11
11
  [false, '0', 'false', 'FALSE'].each do |value|
12
12
  it "returns false for #{value.inspect}" do
13
- expect(filter.cast(value)).to be_falsey
13
+ expect(filter.cast(value, nil)).to be_falsey
14
14
  end
15
15
  end
16
16
  end
@@ -18,7 +18,7 @@ describe ActiveInteraction::BooleanFilter, :filter do
18
18
  context 'truthy' do
19
19
  [true, '1', 'true', 'TRUE'].each do |value|
20
20
  it "returns true for #{value.inspect}" do
21
- expect(filter.cast(value)).to be_truthy
21
+ expect(filter.cast(value, nil)).to be_truthy
22
22
  end
23
23
  end
24
24
  end
@@ -15,7 +15,7 @@ describe ActiveInteraction::DateFilter, :filter do
15
15
  end
16
16
 
17
17
  describe '#cast' do
18
- let(:result) { filter.cast(value) }
18
+ let(:result) { filter.cast(value, nil) }
19
19
 
20
20
  context 'with a Date' do
21
21
  let(:value) { Date.new }
@@ -127,7 +127,7 @@ describe ActiveInteraction::DateFilter, :filter do
127
127
 
128
128
  it 'raises an error' do
129
129
  expect do
130
- filter.default
130
+ filter.default(nil)
131
131
  end.to raise_error ActiveInteraction::InvalidDefaultError
132
132
  end
133
133
  end
@@ -15,7 +15,7 @@ describe ActiveInteraction::DateTimeFilter, :filter do
15
15
  end
16
16
 
17
17
  describe '#cast' do
18
- let(:result) { filter.cast(value) }
18
+ let(:result) { filter.cast(value, nil) }
19
19
 
20
20
  context 'with a Datetime' do
21
21
  let(:value) { DateTime.new }
@@ -138,7 +138,7 @@ describe ActiveInteraction::DateTimeFilter, :filter do
138
138
 
139
139
  it 'raises an error' do
140
140
  expect do
141
- filter.default
141
+ filter.default(nil)
142
142
  end.to raise_error ActiveInteraction::InvalidDefaultError
143
143
  end
144
144
  end
@@ -15,7 +15,7 @@ describe ActiveInteraction::DecimalFilter, :filter do
15
15
  end
16
16
 
17
17
  describe '#cast' do
18
- let(:result) { filter.cast(value) }
18
+ let(:result) { filter.cast(value, nil) }
19
19
 
20
20
  context 'with a Float' do
21
21
  let(:value) { rand }
@@ -7,7 +7,7 @@ describe ActiveInteraction::FileFilter, :filter do
7
7
  it_behaves_like 'a filter'
8
8
 
9
9
  describe '#cast' do
10
- let(:result) { filter.cast(value) }
10
+ let(:result) { filter.cast(value, nil) }
11
11
 
12
12
  context 'with a File' do
13
13
  let(:value) { File.new(__FILE__) }
@@ -7,7 +7,7 @@ describe ActiveInteraction::FloatFilter, :filter do
7
7
  it_behaves_like 'a filter'
8
8
 
9
9
  describe '#cast' do
10
- let(:result) { filter.cast(value) }
10
+ let(:result) { filter.cast(value, nil) }
11
11
 
12
12
  context 'with a Float' do
13
13
  let(:value) { rand }
@@ -25,7 +25,7 @@ describe ActiveInteraction::HashFilter, :filter do
25
25
  end
26
26
 
27
27
  describe '#cast' do
28
- let(:result) { filter.cast(value) }
28
+ let(:result) { filter.cast(value, nil) }
29
29
 
30
30
  context 'with a Hash' do
31
31
  let(:value) { {} }
@@ -94,7 +94,7 @@ describe ActiveInteraction::HashFilter, :filter do
94
94
  end
95
95
 
96
96
  it 'returns the Hash' do
97
- expect(filter.default).to eql options[:default]
97
+ expect(filter.default(nil)).to eql options[:default]
98
98
  end
99
99
  end
100
100
 
@@ -105,7 +105,7 @@ describe ActiveInteraction::HashFilter, :filter do
105
105
 
106
106
  it 'raises an error' do
107
107
  expect do
108
- filter.default
108
+ filter.default(nil)
109
109
  end.to raise_error ActiveInteraction::InvalidDefaultError
110
110
  end
111
111
  end
@@ -7,7 +7,7 @@ describe ActiveInteraction::IntegerFilter, :filter do
7
7
  it_behaves_like 'a filter'
8
8
 
9
9
  describe '#cast' do
10
- let(:result) { filter.cast(value) }
10
+ let(:result) { filter.cast(value, nil) }
11
11
 
12
12
  context 'with an Integer' do
13
13
  let(:value) { rand(1 << 16) }
@@ -11,7 +11,7 @@ describe ActiveInteraction::InterfaceFilter, :filter do
11
11
  before { options[:methods] = [:dump, :load] }
12
12
 
13
13
  describe '#cast' do
14
- let(:result) { filter.cast(value) }
14
+ let(:result) { filter.cast(value, nil) }
15
15
 
16
16
  context 'with a BasicObject' do
17
17
  let(:value) { BasicObject.new }
@@ -15,7 +15,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
15
15
 
16
16
  describe '#cast' do
17
17
  let(:value) { Thing.new }
18
- let(:result) { filter.cast(value) }
18
+ let(:result) { filter.cast(value, nil) }
19
19
 
20
20
  context 'with class as a Class' do
21
21
  it 'returns the instance' do
@@ -29,7 +29,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
29
29
  class Thing; end
30
30
  value = Thing.new
31
31
 
32
- expect(filter.cast(value)).to eql value
32
+ expect(filter.cast(value, nil)).to eql value
33
33
  end
34
34
 
35
35
  it 'handles reconstantizing subclasses' do
@@ -40,7 +40,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
40
40
  class SubThing < Thing; end
41
41
  value = SubThing.new
42
42
 
43
- expect(filter.cast(value)).to eql value
43
+ expect(filter.cast(value, nil)).to eql value
44
44
  end
45
45
 
46
46
  it 'does not overflow the stack' do
@@ -51,7 +51,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
51
51
  end
52
52
 
53
53
  expect do
54
- filter.cast(klass.new)
54
+ filter.cast(klass.new, nil)
55
55
  end.to raise_error ActiveInteraction::InvalidValueError
56
56
  end
57
57
 
@@ -13,7 +13,7 @@ describe ActiveInteraction::StringFilter, :filter do
13
13
  end
14
14
 
15
15
  describe '#cast' do
16
- let(:result) { filter.cast(value) }
16
+ let(:result) { filter.cast(value, nil) }
17
17
 
18
18
  context 'with a String' do
19
19
  let(:value) { SecureRandom.hex }
@@ -7,7 +7,7 @@ describe ActiveInteraction::SymbolFilter, :filter do
7
7
  it_behaves_like 'a filter'
8
8
 
9
9
  describe '#cast' do
10
- let(:result) { filter.cast(value) }
10
+ let(:result) { filter.cast(value, nil) }
11
11
 
12
12
  context 'with a Symbol' do
13
13
  let(:value) { SecureRandom.hex.to_sym }
@@ -37,7 +37,7 @@ describe ActiveInteraction::TimeFilter, :filter do
37
37
  end
38
38
 
39
39
  describe '#cast' do
40
- let(:result) { filter.cast(value) }
40
+ let(:result) { filter.cast(value, nil) }
41
41
 
42
42
  context 'with a Time' do
43
43
  let(:value) { Time.new }
@@ -160,7 +160,7 @@ describe ActiveInteraction::TimeFilter, :filter do
160
160
 
161
161
  it 'raises an error' do
162
162
  expect do
163
- filter.default
163
+ filter.default(nil)
164
164
  end.to raise_error ActiveInteraction::InvalidDefaultError
165
165
  end
166
166
  end
@@ -3,14 +3,21 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe ActiveInteraction::Validation do
6
- describe '.validate(filters, inputs)' do
6
+ describe '.validate(context, filters, inputs)' do
7
7
  let(:inputs) { {} }
8
8
  let(:filter) { ActiveInteraction::Filter.new(:name, {}) }
9
- let(:filters) { { filter.name => filter } }
10
- let(:result) { described_class.validate(filters, inputs) }
9
+ let(:interaction) do
10
+ name = filter.name
11
+ klass = Class.new(ActiveInteraction::Base) { attr_writer(name) }
12
+ klass.filters[name] = filter
13
+ klass.new
14
+ end
15
+ let(:result) do
16
+ described_class.validate(interaction, interaction.class.filters, inputs)
17
+ end
11
18
 
12
19
  context 'no filters are given' do
13
- let(:filters) { {} }
20
+ let(:interaction) { Class.new(ActiveInteraction::Base).new }
14
21
 
15
22
  it 'returns no errors' do
16
23
  expect(result).to eql []
@@ -54,7 +54,7 @@ shared_examples_for 'a filter' do
54
54
  include_context 'optional'
55
55
 
56
56
  it 'returns nil' do
57
- expect(filter.cast(value)).to be_nil
57
+ expect(filter.cast(value, nil)).to be_nil
58
58
  end
59
59
  end
60
60
 
@@ -63,7 +63,7 @@ shared_examples_for 'a filter' do
63
63
 
64
64
  it 'raises an error' do
65
65
  expect do
66
- filter.cast(value)
66
+ filter.cast(value, nil)
67
67
  end.to raise_error ActiveInteraction::MissingValueError
68
68
  end
69
69
 
@@ -72,7 +72,7 @@ shared_examples_for 'a filter' do
72
72
 
73
73
  it 'raises an error' do
74
74
  expect do
75
- filter.cast(value)
75
+ filter.cast(value, nil)
76
76
  end.to raise_error ActiveInteraction::InvalidValueError
77
77
  end
78
78
  end
@@ -86,7 +86,7 @@ shared_examples_for 'a filter' do
86
86
  include_context 'optional'
87
87
 
88
88
  it 'returns the default' do
89
- expect(filter.clean(value)).to eql options[:default]
89
+ expect(filter.clean(value, nil)).to eql options[:default]
90
90
  end
91
91
  end
92
92
 
@@ -95,7 +95,7 @@ shared_examples_for 'a filter' do
95
95
 
96
96
  it 'raises an error' do
97
97
  expect do
98
- filter.clean(value)
98
+ filter.clean(value, nil)
99
99
  end.to raise_error ActiveInteraction::MissingValueError
100
100
  end
101
101
 
@@ -104,7 +104,7 @@ shared_examples_for 'a filter' do
104
104
 
105
105
  it 'raises an error' do
106
106
  expect do
107
- filter.clean(value)
107
+ filter.clean(value, nil)
108
108
  end.to raise_error ActiveInteraction::InvalidValueError
109
109
  end
110
110
  end
@@ -117,7 +117,7 @@ shared_examples_for 'a filter' do
117
117
 
118
118
  it 'raises an error' do
119
119
  expect do
120
- filter.clean(value)
120
+ filter.clean(value, nil)
121
121
  end.to raise_error ActiveInteraction::InvalidDefaultError
122
122
  end
123
123
  end
@@ -128,7 +128,7 @@ shared_examples_for 'a filter' do
128
128
  include_context 'optional'
129
129
 
130
130
  it 'returns the default' do
131
- expect(filter.default).to eql options[:default]
131
+ expect(filter.default(nil)).to eql options[:default]
132
132
  end
133
133
  end
134
134
 
@@ -137,7 +137,7 @@ shared_examples_for 'a filter' do
137
137
 
138
138
  it 'raises an error' do
139
139
  expect do
140
- filter.default
140
+ filter.default(nil)
141
141
  end.to raise_error ActiveInteraction::NoDefaultError
142
142
  end
143
143
  end
@@ -149,7 +149,7 @@ shared_examples_for 'a filter' do
149
149
 
150
150
  it 'raises an error' do
151
151
  expect do
152
- filter.default
152
+ filter.default(nil)
153
153
  end.to raise_error ActiveInteraction::InvalidDefaultError
154
154
  end
155
155
  end
@@ -163,7 +163,7 @@ shared_examples_for 'a filter' do
163
163
  end
164
164
 
165
165
  it 'returns the default' do
166
- expect(filter.default).to eql options[:default].call
166
+ expect(filter.default(nil)).to eql options[:default].call
167
167
  end
168
168
  end
169
169
  end
@@ -27,6 +27,8 @@ shared_examples_for 'an interaction' do |type, generator, filter_options = {}|
27
27
  filter_options.merge(default: generator.call))
28
28
  public_send(type, :defaults_1, :defaults_2,
29
29
  filter_options.merge(default: generator.call))
30
+ public_send(type, :defaults_3,
31
+ filter_options.merge(default: -> { required }))
30
32
  end
31
33
  end
32
34
 
@@ -83,6 +85,10 @@ shared_examples_for 'an interaction' do |type, generator, filter_options = {}|
83
85
  expect(result[:defaults_2]).to_not be_nil
84
86
  end
85
87
 
88
+ it 'evaluates :defaults_3 in the interaction binding' do
89
+ expect(result[:defaults_3]).to eql result[:required]
90
+ end
91
+
86
92
  context 'with inputs[:optional]' do
87
93
  let(:optional) { generator.call }
88
94
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_interaction
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.5
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Lasseigne
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-12 00:00:00.000000000 Z
12
+ date: 2015-12-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - "<"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '5'
54
+ - !ruby/object:Gem::Dependency
55
+ name: benchmark-ips
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.3'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.3'
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: bundler
56
70
  requirement: !ruby/object:Gem::Requirement
@@ -292,7 +306,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
292
306
  version: '0'
293
307
  requirements: []
294
308
  rubyforge_project:
295
- rubygems_version: 2.4.5.1
309
+ rubygems_version: 2.4.5
296
310
  signing_key:
297
311
  specification_version: 4
298
312
  summary: Manage application specific business logic.