active_interaction 0.9.0 → 0.9.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/README.md +4 -4
  4. data/lib/active_interaction.rb +2 -0
  5. data/lib/active_interaction/base.rb +26 -14
  6. data/lib/active_interaction/errors.rb +7 -10
  7. data/lib/active_interaction/filter.rb +10 -10
  8. data/lib/active_interaction/filters.rb +2 -0
  9. data/lib/active_interaction/filters/abstract_date_time_filter.rb +4 -2
  10. data/lib/active_interaction/filters/abstract_numeric_filter.rb +3 -1
  11. data/lib/active_interaction/filters/array_filter.rb +5 -3
  12. data/lib/active_interaction/filters/boolean_filter.rb +2 -0
  13. data/lib/active_interaction/filters/date_filter.rb +2 -0
  14. data/lib/active_interaction/filters/date_time_filter.rb +2 -0
  15. data/lib/active_interaction/filters/file_filter.rb +2 -0
  16. data/lib/active_interaction/filters/float_filter.rb +2 -0
  17. data/lib/active_interaction/filters/hash_filter.rb +7 -6
  18. data/lib/active_interaction/filters/integer_filter.rb +2 -0
  19. data/lib/active_interaction/filters/model_filter.rb +2 -0
  20. data/lib/active_interaction/filters/string_filter.rb +2 -0
  21. data/lib/active_interaction/filters/symbol_filter.rb +2 -0
  22. data/lib/active_interaction/filters/time_filter.rb +2 -0
  23. data/lib/active_interaction/modules/active_model.rb +2 -0
  24. data/lib/active_interaction/modules/core.rb +4 -1
  25. data/lib/active_interaction/modules/method_missing.rb +2 -0
  26. data/lib/active_interaction/modules/overload_hash.rb +2 -0
  27. data/lib/active_interaction/modules/validation.rb +10 -5
  28. data/lib/active_interaction/version.rb +4 -1
  29. data/spec/active_interaction/base_spec.rb +60 -35
  30. data/spec/active_interaction/errors_spec.rb +48 -14
  31. data/spec/active_interaction/filter_spec.rb +4 -2
  32. data/spec/active_interaction/filters/array_filter_spec.rb +13 -6
  33. data/spec/active_interaction/filters/boolean_filter_spec.rb +2 -0
  34. data/spec/active_interaction/filters/date_filter_spec.rb +6 -4
  35. data/spec/active_interaction/filters/date_time_filter_spec.rb +6 -4
  36. data/spec/active_interaction/filters/file_filter_spec.rb +2 -0
  37. data/spec/active_interaction/filters/float_filter_spec.rb +4 -2
  38. data/spec/active_interaction/filters/hash_filter_spec.rb +16 -4
  39. data/spec/active_interaction/filters/integer_filter_spec.rb +4 -2
  40. data/spec/active_interaction/filters/model_filter_spec.rb +4 -2
  41. data/spec/active_interaction/filters/string_filter_spec.rb +2 -0
  42. data/spec/active_interaction/filters/symbol_filter_spec.rb +2 -0
  43. data/spec/active_interaction/filters/time_filter_spec.rb +6 -4
  44. data/spec/active_interaction/filters_spec.rb +2 -0
  45. data/spec/active_interaction/i18n_spec.rb +9 -9
  46. data/spec/active_interaction/integration/array_interaction_spec.rb +10 -8
  47. data/spec/active_interaction/integration/boolean_interaction_spec.rb +2 -0
  48. data/spec/active_interaction/integration/date_interaction_spec.rb +2 -0
  49. data/spec/active_interaction/integration/date_time_interaction_spec.rb +2 -0
  50. data/spec/active_interaction/integration/file_interaction_spec.rb +2 -0
  51. data/spec/active_interaction/integration/float_interaction_spec.rb +2 -0
  52. data/spec/active_interaction/integration/hash_interaction_spec.rb +10 -8
  53. data/spec/active_interaction/integration/integer_interaction_spec.rb +2 -0
  54. data/spec/active_interaction/integration/model_interaction_spec.rb +3 -1
  55. data/spec/active_interaction/integration/string_interaction_spec.rb +2 -0
  56. data/spec/active_interaction/integration/symbol_interaction_spec.rb +2 -0
  57. data/spec/active_interaction/integration/time_interaction_spec.rb +9 -7
  58. data/spec/active_interaction/modules/active_model_spec.rb +2 -0
  59. data/spec/active_interaction/modules/core_spec.rb +12 -7
  60. data/spec/active_interaction/modules/method_missing_spec.rb +12 -10
  61. data/spec/active_interaction/modules/overload_hash_spec.rb +7 -5
  62. data/spec/active_interaction/modules/validation_spec.rb +5 -2
  63. data/spec/spec_helper.rb +4 -0
  64. data/spec/support/filters.rb +18 -16
  65. data/spec/support/interactions.rb +13 -11
  66. metadata +20 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1139d1df0d150418f22b231b09423c894ba98c41
4
- data.tar.gz: c53767591c098f28c46ffa8ae77fb31ac714e310
3
+ metadata.gz: 0449466d5aadcc60fb21146f2f69cad47097698a
4
+ data.tar.gz: d88a740e6c885e713a2829b7a26902e9712a57c8
5
5
  SHA512:
6
- metadata.gz: 5524134f37f76b6252d1ee82a2fe9d879aae1debec5d46679b66eb608e42bd49668c59532c5e2fda8f64999b5582649fb090c78e0c9c7048df2d05cd7e729474
7
- data.tar.gz: 591d0b74feed33a7a7d39ebe67f61adea4c7f5721541d9c570ef39c8dd06b53f4cfd74ee8bac8dc8a78508c447d942a7e0cacbb80813392640ddce8d79f9b512
6
+ metadata.gz: 3563d4d5944e8316c3a75c9450c52a411a626436b9acc87380b92890cd393f1cd743f1b6cd2b3a7159a5e963aac06c2bc21dcdb494616337c4d2fb654cfa0ac5
7
+ data.tar.gz: 58cb5f5101acce859c491c3eb3a5d8c0117d46f31c966007f3d86a34244c87ac8810493204161dcdee1d840d5954730d88b06c6173e10cdf9366f41542feec66
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # [Master][]
2
2
 
3
+ # [0.9.1][] (2013-12-17)
4
+
5
+ - Fix I18n deprecation warning.
6
+ - Raise `ArgumentError` when running an interaction with non-hash inputs.
7
+ - For compatibility with `ActiveRecord::Errors`, support indifferent access of
8
+ `ActiveInteraction::Errors`.
9
+ - Fix losing filters when using inheritance.
10
+
3
11
  # [0.9.0][] (2013-12-02)
4
12
 
5
13
  - Add experimental composition implementation
@@ -84,7 +92,8 @@
84
92
 
85
93
  - Initial release.
86
94
 
87
- [master]: https://github.com/orgsync/active_interaction/compare/v0.9.0...master
95
+ [master]: https://github.com/orgsync/active_interaction/compare/v0.9.1...master
96
+ [0.9.1]: https://github.com/orgsync/active_interaction/compare/v0.9.0...0.9.1
88
97
  [0.9.0]: https://github.com/orgsync/active_interaction/compare/v0.9.0...0.9.0
89
98
  [0.8.0]: https://github.com/orgsync/active_interaction/compare/v0.7.0...v0.8.0
90
99
  [0.7.0]: https://github.com/orgsync/active_interaction/compare/v0.6.1...v0.7.0
data/README.md CHANGED
@@ -25,7 +25,7 @@ This project uses [semantic versioning][].
25
25
  Add it to your Gemfile:
26
26
 
27
27
  ```ruby
28
- gem 'active_interaction', '~> 0.9.0'
28
+ gem 'active_interaction', '~> 0.9.1'
29
29
  ```
30
30
 
31
31
  And then execute:
@@ -43,8 +43,8 @@ $ gem install active_interaction
43
43
  ## What do I get?
44
44
 
45
45
  ActiveInteraction::Base lets you create interaction models. These
46
- models ensure that certain options are provided and that those
47
- options are in the format you want them in. If the options are valid
46
+ models ensure that certain inputs are provided and that those
47
+ inputs are in the format you want them in. If the inputs are valid
48
48
  it will call `execute`, store the return value of that method in
49
49
  `result`, and return an instance of your ActiveInteraction::Base
50
50
  subclass. Let's look at a simple example:
@@ -61,7 +61,7 @@ class UserSignup < ActiveInteraction::Base
61
61
  # ActiveRecord validations
62
62
  validates :email, format: EMAIL_REGEX
63
63
 
64
- # The execute method is called only if the options validate. It
64
+ # The execute method is called only if the inputs validate. It
65
65
  # does your business action. The return value will be stored in
66
66
  # `result`.
67
67
  def execute
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'active_model'
2
4
 
3
5
  require 'active_interaction/version'
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'active_support/core_ext/hash/indifferent_access'
2
4
 
3
5
  module ActiveInteraction
@@ -33,26 +35,29 @@ module ActiveInteraction
33
35
 
34
36
  validate :input_errors, :runtime_errors
35
37
 
36
- # @param options [Hash{Symbol => Object}] Attribute values to set.
38
+ # @param inputs [Hash{Symbol => Object}] Attribute values to set.
37
39
  #
38
40
  # @private
39
- def initialize(options = {})
41
+ def initialize(inputs = {})
42
+ fail ArgumentError, 'inputs must be a hash' unless inputs.is_a?(Hash)
43
+
40
44
  @_interaction_errors = Errors.new(self)
41
45
  @_interaction_result = nil
42
46
  @_interaction_runtime_errors = nil
43
47
 
44
- options = options.symbolize_keys
45
- options.each do |key, value|
48
+ inputs.each do |key, value|
46
49
  if key.to_s.start_with?('_interaction_')
47
- raise InvalidValueError, key.inspect
50
+ fail InvalidValueError, key.inspect
48
51
  end
49
52
 
50
53
  instance_variable_set("@#{key}", value)
51
54
  end
52
55
 
56
+ inputs = inputs.symbolize_keys
53
57
  self.class.filters.each do |filter|
54
58
  begin
55
- send("#{filter.name}=", filter.clean(options[filter.name]))
59
+ send("#{filter.name}=", filter.clean(inputs[filter.name]))
60
+ # rubocop: disable HandleExceptions
56
61
  rescue InvalidValueError, MissingValueError
57
62
  # Validators (#input_errors) will add errors if appropriate.
58
63
  end
@@ -66,9 +71,8 @@ module ActiveInteraction
66
71
  #
67
72
  # @since 0.6.0
68
73
  def inputs
69
- self.class.filters.reduce({}) do |h, filter|
74
+ self.class.filters.each_with_object({}) do |filter, h|
70
75
  h[filter.name] = send(filter.name)
71
- h
72
76
  end
73
77
  end
74
78
 
@@ -81,7 +85,7 @@ module ActiveInteraction
81
85
  #
82
86
  # @abstract
83
87
  def execute
84
- raise NotImplementedError
88
+ fail NotImplementedError
85
89
  end
86
90
 
87
91
  # Returns the output from {#execute} if there are no validation errors or
@@ -123,6 +127,7 @@ module ActiveInteraction
123
127
  result = transaction do
124
128
  begin
125
129
  interaction.execute
130
+ # rubocop:disable HandleExceptions
126
131
  rescue Interrupt
127
132
  # Inner interaction failed. #compose handles merging errors.
128
133
  end
@@ -141,11 +146,11 @@ module ActiveInteraction
141
146
  # @private
142
147
  def self.method_missing(*args, &block)
143
148
  super do |klass, names, options|
144
- raise InvalidFilterError, 'missing attribute name' if names.empty?
149
+ fail InvalidFilterError, 'missing attribute name' if names.empty?
145
150
 
146
151
  names.each do |attribute|
147
152
  if attribute.to_s.start_with?('_interaction_')
148
- raise InvalidFilterError, attribute.inspect
153
+ fail InvalidFilterError, attribute.inspect
149
154
  end
150
155
 
151
156
  filter = klass.new(attribute, options, &block)
@@ -173,8 +178,8 @@ module ActiveInteraction
173
178
  end
174
179
  end
175
180
 
176
- def compose(interaction, options = {})
177
- outcome = interaction.run(options)
181
+ def compose(interaction, inputs = {})
182
+ outcome = interaction.run(inputs)
178
183
  return outcome.result if outcome.valid?
179
184
 
180
185
  # This can't use Errors#merge! because the errors have to be added to
@@ -183,7 +188,14 @@ module ActiveInteraction
183
188
  errors.add(:base, message) unless errors.added?(:base, message)
184
189
  end
185
190
 
186
- raise Interrupt
191
+ fail Interrupt
192
+ end
193
+
194
+ def self.inherited(subclass)
195
+ instance_var = :@_interaction_filters
196
+
197
+ subclass.instance_variable_set(
198
+ instance_var, instance_variable_get(instance_var))
187
199
  end
188
200
  end
189
201
  end
@@ -1,3 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ # rubocop:disable Documentation
1
4
  module ActiveInteraction
2
5
  # Top-level error class. All other errors subclass this.
3
6
  Error = Class.new(StandardError)
@@ -66,13 +69,13 @@ module ActiveInteraction
66
69
 
67
70
  # @private
68
71
  def initialize(*args)
69
- @symbolic = {}
72
+ @symbolic = {}.with_indifferent_access
70
73
  super
71
74
  end
72
75
 
73
76
  # @private
74
77
  def initialize_dup(other)
75
- @symbolic = other.symbolic.dup
78
+ @symbolic = other.symbolic.with_indifferent_access
76
79
  super
77
80
  end
78
81
 
@@ -89,17 +92,11 @@ module ActiveInteraction
89
92
  # @return [Errors]
90
93
  def merge!(other)
91
94
  other.symbolic.each do |attribute, symbols|
92
- symbols.each do |symbol|
93
- add_sym(attribute, symbol)
94
- end
95
+ symbols.each { |s| add_sym(attribute, s) }
95
96
  end
96
97
 
97
98
  other.messages.each do |attribute, messages|
98
- messages.each do |message|
99
- unless added?(attribute, message)
100
- add(attribute, message)
101
- end
102
- end
99
+ messages.each { |m| add(attribute, m) unless added?(attribute, m) }
103
100
  end
104
101
 
105
102
  self
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require 'active_support/inflector'
2
4
 
3
5
  module ActiveInteraction
@@ -76,17 +78,15 @@ module ActiveInteraction
76
78
  # @see .factory
77
79
  def slug
78
80
  match = CLASS_REGEXP.match(name)
79
- raise InvalidClassError, name unless match
81
+ fail InvalidClassError, name unless match
80
82
  match.captures.first.underscore.to_sym
81
83
  end
82
84
 
83
85
  # @private
84
86
  def inherited(klass)
85
- begin
86
- CLASSES[klass.slug] = klass
87
- rescue InvalidClassError
88
- # Ignore classes with invalid slugs.
89
- end
87
+ CLASSES[klass.slug] = klass
88
+ rescue InvalidClassError
89
+ CLASSES[klass.name.to_sym] = klass
90
90
  end
91
91
  end
92
92
 
@@ -159,7 +159,7 @@ module ActiveInteraction
159
159
  # @raise [InvalidDefaultError] if the default value is invalid
160
160
  # @raise [NoDefaultError] if there is no default value
161
161
  def default
162
- raise NoDefaultError, name unless has_default?
162
+ fail NoDefaultError, name unless has_default?
163
163
 
164
164
  cast(options[:default])
165
165
  rescue InvalidValueError, MissingValueError
@@ -193,18 +193,18 @@ module ActiveInteraction
193
193
  #
194
194
  # @return [Boolean]
195
195
  def has_default?
196
- options.has_key?(:default)
196
+ options.key?(:default)
197
197
  end
198
198
 
199
199
  # @private
200
200
  def cast(value)
201
201
  case value
202
202
  when NilClass
203
- raise MissingValueError, name unless has_default?
203
+ fail MissingValueError, name unless has_default?
204
204
 
205
205
  nil
206
206
  else
207
- raise InvalidValueError, "#{name}: #{value.inspect}"
207
+ fail InvalidValueError, "#{name}: #{value.inspect}"
208
208
  end
209
209
  end
210
210
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # A collection of {Filter}s.
3
5
  #
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  class AbstractDateTimeFilter < Filter
@@ -27,11 +29,11 @@ module ActiveInteraction
27
29
  end
28
30
 
29
31
  def has_format?
30
- options.has_key?(:format)
32
+ options.key?(:format)
31
33
  end
32
34
 
33
35
  def klass
34
- raise NotImplementedError
36
+ fail NotImplementedError
35
37
  end
36
38
  end
37
39
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  # @private
3
5
  class AbstractNumericFilter < Filter
@@ -19,7 +21,7 @@ module ActiveInteraction
19
21
  private
20
22
 
21
23
  def klass
22
- raise NotImplementedError
24
+ fail NotImplementedError
23
25
  end
24
26
  end
25
27
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -45,13 +47,13 @@ module ActiveInteraction
45
47
  filter = klass.new(name, options, &block)
46
48
 
47
49
  if filters.any?
48
- raise InvalidFilterError, 'multiple filters in array block'
50
+ fail InvalidFilterError, 'multiple filters in array block'
49
51
  end
50
52
  unless names.empty?
51
- raise InvalidFilterError, 'attribute names in array block'
53
+ fail InvalidFilterError, 'attribute names in array block'
52
54
  end
53
55
  if filter.has_default?
54
- raise InvalidDefaultError, 'default values in array block'
56
+ fail InvalidDefaultError, 'default values in array block'
55
57
  end
56
58
 
57
59
  filters.add(filter)
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -31,10 +33,9 @@ module ActiveInteraction
31
33
  case value
32
34
  when Hash
33
35
  value = value.symbolize_keys
34
- filters.reduce(strip? ? {} : value) do |h, f|
35
- k = f.name
36
- h[k] = f.clean(value[k])
37
- h
36
+ filters.each_with_object(strip? ? {} : value) do |filter, h|
37
+ k = filter.name
38
+ h[k] = filter.clean(value[k])
38
39
  end
39
40
  else
40
41
  super
@@ -43,7 +44,7 @@ module ActiveInteraction
43
44
 
44
45
  def default
45
46
  if options[:default].is_a?(Hash) && !options[:default].empty?
46
- raise InvalidDefaultError, "#{name}: #{options[:default].inspect}"
47
+ fail InvalidDefaultError, "#{name}: #{options[:default].inspect}"
47
48
  end
48
49
 
49
50
  super
@@ -51,7 +52,7 @@ module ActiveInteraction
51
52
 
52
53
  def method_missing(*args, &block)
53
54
  super(*args) do |klass, names, options|
54
- raise InvalidFilterError, 'missing attribute name' if names.empty?
55
+ fail InvalidFilterError, 'missing attribute name' if names.empty?
55
56
 
56
57
  names.each do |name|
57
58
  filters.add(klass.new(name, options, &block))
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  module ActiveInteraction
2
4
  class Base
3
5
  # Creates accessors for the attributes and ensures that values passed to