light-service 0.6.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +34 -0
  3. data/.travis.yml +16 -2
  4. data/Appraisals +7 -0
  5. data/Gemfile +2 -0
  6. data/README.md +126 -16
  7. data/RELEASES.md +4 -0
  8. data/Rakefile +3 -0
  9. data/gemfiles/activesupport_3.gemfile +8 -0
  10. data/gemfiles/activesupport_3.gemfile.lock +63 -0
  11. data/gemfiles/activesupport_4.gemfile +8 -0
  12. data/gemfiles/activesupport_4.gemfile.lock +71 -0
  13. data/lib/light-service.rb +1 -1
  14. data/lib/light-service/action.rb +6 -8
  15. data/lib/light-service/configuration.rb +0 -2
  16. data/lib/light-service/context.rb +32 -22
  17. data/lib/light-service/context/key_verifier.rb +87 -83
  18. data/lib/light-service/localization_adapter.rb +10 -7
  19. data/lib/light-service/organizer.rb +6 -3
  20. data/lib/light-service/organizer/with_reducer.rb +53 -39
  21. data/lib/light-service/organizer/with_reducer_factory.rb +3 -4
  22. data/lib/light-service/organizer/with_reducer_log_decorator.rb +81 -51
  23. data/lib/light-service/version.rb +2 -1
  24. data/light-service.gemspec +4 -4
  25. data/resources/fail_actions.png +0 -0
  26. data/resources/skip_actions.png +0 -0
  27. data/spec/acceptance/around_each_spec.rb +27 -0
  28. data/spec/acceptance/include_warning_spec.rb +6 -2
  29. data/spec/acceptance/log_from_organizer_spec.rb +39 -18
  30. data/spec/acceptance/message_localization_spec.rb +23 -23
  31. data/spec/acceptance/rollback_spec.rb +1 -3
  32. data/spec/action_expected_keys_spec.rb +32 -19
  33. data/spec/action_promised_keys_spec.rb +72 -54
  34. data/spec/action_spec.rb +23 -5
  35. data/spec/context_spec.rb +21 -17
  36. data/spec/localization_adapter_spec.rb +14 -10
  37. data/spec/organizer/with_reducer_spec.rb +19 -2
  38. data/spec/organizer_key_aliases_spec.rb +6 -5
  39. data/spec/organizer_spec.rb +32 -56
  40. data/spec/sample/calculates_tax_spec.rb +17 -9
  41. data/spec/sample/provides_free_shipping_action_spec.rb +3 -7
  42. data/spec/sample/tax/calculates_order_tax_action.rb +3 -2
  43. data/spec/sample/tax/calculates_tax.rb +3 -4
  44. data/spec/sample/tax/looks_up_tax_percentage_action.rb +10 -8
  45. data/spec/sample/tax/provides_free_shipping_action.rb +2 -4
  46. data/spec/spec_helper.rb +0 -1
  47. data/spec/test_doubles.rb +38 -15
  48. metadata +38 -28
@@ -1,6 +1,6 @@
1
1
  require 'logger'
2
2
 
3
- require "light-service/version"
3
+ require 'light-service/version'
4
4
 
5
5
  require 'light-service/errors'
6
6
  require 'light-service/configuration'
@@ -1,12 +1,13 @@
1
1
  module LightService
2
2
  module Action
3
-
4
3
  def self.extended(base_class)
5
4
  base_class.extend Macros
6
5
  end
7
6
 
8
7
  def self.included(base_class)
9
- ActiveSupport::Deprecation.warn "including LightService::Action is deprecated. Please use `extend LightService::Action` instead"
8
+ msg = "including LightService::Action is deprecated. " \
9
+ "Please use `extend LightService::Action` instead"
10
+ ActiveSupport::Deprecation.warn(msg)
10
11
  base_class.extend Macros
11
12
  end
12
13
 
@@ -46,22 +47,20 @@ module LightService
46
47
  end
47
48
 
48
49
  def rolled_back
49
- raise "`rolled_back` macro can not be invoked again" if self.respond_to?(:rollback)
50
+ msg = "`rolled_back` macro can not be invoked again"
51
+ fail msg if respond_to?(:rollback)
50
52
 
51
53
  define_singleton_method :rollback do |context = {}|
52
54
  yield(context)
53
55
 
54
56
  context
55
57
  end
56
-
57
58
  end
58
59
 
59
60
  private
60
61
 
61
62
  def create_action_context(context)
62
- if context.is_a? LightService::Context
63
- return context
64
- end
63
+ return context if context.is_a? LightService::Context
65
64
 
66
65
  LightService::Context.make(context)
67
66
  end
@@ -70,6 +69,5 @@ module LightService
70
69
  expected_keys + promised_keys
71
70
  end
72
71
  end
73
-
74
72
  end
75
73
  end
@@ -1,6 +1,5 @@
1
1
  module LightService
2
2
  class Configuration
3
-
4
3
  class << self
5
4
  attr_writer :logger, :localization_adapter
6
5
 
@@ -20,6 +19,5 @@ module LightService
20
19
  logger
21
20
  end
22
21
  end
23
-
24
22
  end
25
23
  end
@@ -7,28 +7,32 @@ module LightService
7
7
  class Context < Hash
8
8
  attr_accessor :message, :error_code, :current_action
9
9
 
10
- def initialize(context={}, outcome=Outcomes::SUCCESS, message='', error_code=nil)
11
- @outcome, @message, @error_code = outcome, message, error_code
10
+ def initialize(context = {},
11
+ outcome = Outcomes::SUCCESS,
12
+ message = '',
13
+ error_code = nil)
14
+ @outcome = outcome
15
+ @message = message
16
+ @error_code = error_code
12
17
  @skip_all = false
13
- context.to_hash.each {|k,v| self[k] = v}
18
+ context.to_hash.each { |k, v| self[k] = v }
14
19
  self
15
20
  end
16
21
 
17
- def self.make(context={})
18
- unless context.is_a? Hash or context.is_a? LightService::Context
19
- raise ArgumentError, 'Argument must be Hash or LightService::Context'
22
+ def self.make(context = {})
23
+ unless context.is_a?(Hash) || context.is_a?(LightService::Context)
24
+ msg = 'Argument must be Hash or LightService::Context'
25
+ fail ArgumentError, msg
20
26
  end
21
27
 
22
- unless context.is_a?(Context)
23
- context = self.new(context)
24
- end
28
+ context = new(context) unless context.is_a?(Context)
25
29
 
26
- context.set_aliases(context.delete(:_aliases)) if context[:_aliases]
30
+ context.assign_aliases(context.delete(:_aliases)) if context[:_aliases]
27
31
  context
28
32
  end
29
33
 
30
34
  def add_to_context(values)
31
- self.merge! values
35
+ merge! values
32
36
  end
33
37
 
34
38
  def success?
@@ -44,16 +48,20 @@ module LightService
44
48
  end
45
49
 
46
50
  def outcome
47
- ActiveSupport::Deprecation.warn '`Context#outcome` attribute reader is DEPRECATED and will be removed'
51
+ msg = '`Context#outcome` attribute reader is ' \
52
+ 'DEPRECATED and will be removed'
53
+ ActiveSupport::Deprecation.warn(msg)
48
54
  @outcome
49
55
  end
50
56
 
51
- def succeed!(message=nil, options={})
52
- @message = Configuration.localization_adapter.success(message, current_action, options)
57
+ def succeed!(message = nil, options = {})
58
+ @message = Configuration.localization_adapter.success(message,
59
+ current_action,
60
+ options)
53
61
  @outcome = Outcomes::SUCCESS
54
62
  end
55
63
 
56
- def fail!(message=nil, options_or_error_code={})
64
+ def fail!(message = nil, options_or_error_code = {})
57
65
  options_or_error_code ||= {}
58
66
 
59
67
  if options_or_error_code.is_a?(Hash)
@@ -64,17 +72,19 @@ module LightService
64
72
  options = {}
65
73
  end
66
74
 
67
- @message = Configuration.localization_adapter.failure(message, current_action, options)
75
+ @message = Configuration.localization_adapter.failure(message,
76
+ current_action,
77
+ options)
68
78
  @error_code = error_code
69
79
  @outcome = Outcomes::FAILURE
70
80
  end
71
81
 
72
- def fail_with_rollback!(message=nil, error_code=nil)
82
+ def fail_with_rollback!(message = nil, error_code = nil)
73
83
  fail!(message, error_code)
74
- raise FailWithRollbackError.new
84
+ fail(FailWithRollbackError)
75
85
  end
76
86
 
77
- def skip_all!(message=nil)
87
+ def skip_all!(message = nil)
78
88
  @message = message
79
89
  @skip_all = true
80
90
  end
@@ -86,13 +96,13 @@ module LightService
86
96
  def define_accessor_methods_for_keys(keys)
87
97
  return if keys.nil?
88
98
  keys.each do |key|
89
- next if self.respond_to?(key.to_sym)
90
- define_singleton_method("#{key}") { self.fetch(key) }
99
+ next if respond_to?(key.to_sym)
100
+ define_singleton_method(key.to_s) { fetch(key) }
91
101
  define_singleton_method("#{key}=") { |value| self[key] = value }
92
102
  end
93
103
  end
94
104
 
95
- def set_aliases(aliases)
105
+ def assign_aliases(aliases)
96
106
  @aliases = aliases
97
107
 
98
108
  aliases.each_pair do |key, key_alias|
@@ -1,114 +1,118 @@
1
- module LightService; class Context
2
- class KeyVerifier
3
- attr_reader :context, :action
1
+ module LightService
2
+ class Context
3
+ class KeyVerifier
4
+ attr_reader :context, :action
5
+
6
+ def initialize(context, action)
7
+ @context = context
8
+ @action = action
9
+ end
4
10
 
5
- def initialize(context, action)
6
- @context = context
7
- @action = action
8
- end
11
+ def are_all_keys_in_context?(keys)
12
+ not_found_keys = keys_not_found(keys)
13
+ !not_found_keys.any?
14
+ end
9
15
 
10
- def are_all_keys_in_context?(keys)
11
- not_found_keys = keys_not_found(keys)
12
- !not_found_keys.any?
13
- end
16
+ def keys_not_found(keys)
17
+ keys ||= context.keys
18
+ keys - context.keys
19
+ end
14
20
 
15
- def keys_not_found(keys)
16
- keys ||= context.keys
17
- keys - context.keys
18
- end
21
+ def format_keys(keys)
22
+ keys.map { |k| ":#{k}" }.join(', ')
23
+ end
19
24
 
20
- def format_keys(keys)
21
- keys.map { |k| ":#{k}"}.join(', ')
22
- end
25
+ def error_message
26
+ "#{type_name} #{format_keys(keys_not_found(keys))} " \
27
+ "to be in the context during #{action}"
28
+ end
23
29
 
24
- def error_message
25
- "#{type_name} #{format_keys(keys_not_found(keys))} to be in the context during #{action}"
26
- end
30
+ def throw_error_predicate(_keys)
31
+ fail NotImplementedError, 'Sorry, you have to override length'
32
+ end
27
33
 
28
- def throw_error_predicate(keys)
29
- raise NotImplementedError, 'Sorry, you have to override length'
30
- end
34
+ def verify
35
+ return context if context.failure?
31
36
 
32
- def verify
33
- return context if context.failure?
37
+ if throw_error_predicate(keys)
38
+ Configuration.logger.error error_message
39
+ fail error_to_throw, error_message
40
+ end
34
41
 
35
- if throw_error_predicate(keys)
36
- Configuration.logger.error error_message
37
- fail error_to_throw, error_message
42
+ context
38
43
  end
39
44
 
40
- context
41
- end
42
-
43
- def self.verify_keys(context, action, &block)
44
- ReservedKeysVerifier.new(context, action).verify
45
- ExpectedKeyVerifier.new(context, action).verify
45
+ def self.verify_keys(context, action, &block)
46
+ ReservedKeysVerifier.new(context, action).verify
47
+ ExpectedKeyVerifier.new(context, action).verify
46
48
 
47
- block.call
49
+ block.call
48
50
 
49
- PromisedKeyVerifier.new(context, action).verify
51
+ PromisedKeyVerifier.new(context, action).verify
52
+ end
50
53
  end
51
- end
52
54
 
53
- class ExpectedKeyVerifier < KeyVerifier
54
- def type_name
55
- "expected"
56
- end
55
+ class ExpectedKeyVerifier < KeyVerifier
56
+ def type_name
57
+ "expected"
58
+ end
57
59
 
58
- def keys
59
- action.expected_keys
60
- end
60
+ def keys
61
+ action.expected_keys
62
+ end
61
63
 
62
- def error_to_throw
63
- ExpectedKeysNotInContextError
64
- end
64
+ def error_to_throw
65
+ ExpectedKeysNotInContextError
66
+ end
65
67
 
66
- def throw_error_predicate(keys)
67
- !are_all_keys_in_context?(keys)
68
+ def throw_error_predicate(keys)
69
+ !are_all_keys_in_context?(keys)
70
+ end
68
71
  end
69
- end
70
72
 
71
- class PromisedKeyVerifier < KeyVerifier
72
- def type_name
73
- "promised"
74
- end
73
+ class PromisedKeyVerifier < KeyVerifier
74
+ def type_name
75
+ "promised"
76
+ end
75
77
 
76
- def keys
77
- action.promised_keys
78
- end
78
+ def keys
79
+ action.promised_keys
80
+ end
79
81
 
80
- def error_to_throw
81
- PromisedKeysNotInContextError
82
- end
82
+ def error_to_throw
83
+ PromisedKeysNotInContextError
84
+ end
83
85
 
84
- def throw_error_predicate(keys)
85
- !are_all_keys_in_context?(keys)
86
+ def throw_error_predicate(keys)
87
+ !are_all_keys_in_context?(keys)
88
+ end
86
89
  end
87
- end
88
90
 
89
- class ReservedKeysVerifier < KeyVerifier
90
- def violated_keys
91
- (action.promised_keys + action.expected_keys) & reserved_keys
92
- end
91
+ class ReservedKeysVerifier < KeyVerifier
92
+ def violated_keys
93
+ (action.promised_keys + action.expected_keys) & reserved_keys
94
+ end
93
95
 
94
- def error_message
95
- "promised or expected keys cannot be a reserved key: [#{format_keys(violated_keys)}]"
96
- end
96
+ def error_message
97
+ "promised or expected keys cannot be a " \
98
+ "reserved key: [#{format_keys(violated_keys)}]"
99
+ end
97
100
 
98
- def keys
99
- violated_keys
100
- end
101
+ def keys
102
+ violated_keys
103
+ end
101
104
 
102
- def error_to_throw
103
- ReservedKeysInContextError
104
- end
105
+ def error_to_throw
106
+ ReservedKeysInContextError
107
+ end
105
108
 
106
- def throw_error_predicate(keys)
107
- keys.any?
108
- end
109
+ def throw_error_predicate(keys)
110
+ keys.any?
111
+ end
109
112
 
110
- def reserved_keys
111
- [:message, :error_code, :current_action].freeze
113
+ def reserved_keys
114
+ [:message, :error_code, :current_action].freeze
115
+ end
112
116
  end
113
117
  end
114
- end; end
118
+ end
@@ -1,22 +1,25 @@
1
1
  module LightService
2
2
  class LocalizationAdapter
3
- def failure(message_or_key, action_class, i18n_options={})
3
+ def failure(message_or_key, action_class, i18n_options = {})
4
4
  find_translated_message(message_or_key,
5
5
  action_class,
6
6
  i18n_options,
7
- {:type => :failure})
7
+ :type => :failure)
8
8
  end
9
9
 
10
- def success(message_or_key, action_class, i18n_options={})
10
+ def success(message_or_key, action_class, i18n_options = {})
11
11
  find_translated_message(message_or_key,
12
12
  action_class,
13
13
  i18n_options,
14
- {:type => :success})
14
+ :type => :success)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
- def find_translated_message(message_or_key, action_class, i18n_options, type)
19
+ def find_translated_message(message_or_key,
20
+ action_class,
21
+ i18n_options,
22
+ type)
20
23
  if message_or_key.is_a?(Symbol)
21
24
  i18n_options.merge!(type)
22
25
  translate(message_or_key, action_class, i18n_options)
@@ -25,11 +28,11 @@ module LightService
25
28
  end
26
29
  end
27
30
 
28
- def translate(key, action_class, options={})
31
+ def translate(key, action_class, options = {})
29
32
  type = options.delete(:type)
30
33
 
31
34
  scope = i18n_scope_from_class(action_class, type)
32
- options.merge!(scope: scope)
35
+ options[:scope] = scope
33
36
 
34
37
  I18n.t(key, options)
35
38
  end
@@ -4,16 +4,19 @@ module LightService
4
4
  base_class.extend ClassMethods
5
5
  base_class.extend Macros
6
6
  end
7
+
7
8
  def self.included(base_class)
8
- ActiveSupport::Deprecation.warn "including LightService::Organizer is deprecated. Please use `extend LightService::Organizer` instead"
9
+ warning_msg = "including LightService::Organizer is deprecated. " \
10
+ "Please use `extend LightService::Organizer` instead"
11
+ ActiveSupport::Deprecation.warn(warning_msg)
9
12
  base_class.extend ClassMethods
10
13
  base_class.extend Macros
11
14
  end
12
15
 
13
16
  # In case this module is included
14
17
  module ClassMethods
15
- def with(data={})
16
- data.merge!(:_aliases => @aliases) if @aliases
18
+ def with(data = {})
19
+ data[:_aliases] = @aliases if @aliases
17
20
  WithReducerFactory.make(self).with(data)
18
21
  end
19
22